Vert.x with Mutiny (Reactive)
Mutiny Uni/Multi over the callback API — composable reactive workflows.
# CLAUDE.md — Vert.x with Mutiny
## Why Mutiny
- **Mutiny** (`io.smallrye.mutiny:mutiny`) is a reactive library tightly integrated with Vert.x and Quarkus.
- Cleaner than callback Vert.x. More fluent than Vert.x `Future`. Reactive Streams compatible (interop with Reactor, RxJava).
- For new Vert.x code, prefer Mutiny or `Future`. Avoid the original callback API.
## Uni and Multi
- `Uni<T>` — 0..1 element with possible failure. Most use cases.
- `Multi<T>` — 0..N elements (a stream). For event streams, paginated reads, message subscriptions.
## Mutiny-flavored Vert.x
- Use `io.vertx.mutiny.*` packages — every Vert.x API has a Mutiny version returning `Uni`/`Multi`:
```java
io.vertx.mutiny.core.Vertx vertx = io.vertx.mutiny.core.Vertx.vertx();
io.vertx.mutiny.core.http.HttpClient client = vertx.createHttpClient();
Uni<String> body = client.request(GET, "https://example.com").flatMap(req -> req.send().flatMap(HttpClientResponse::body)).map(Buffer::toString);
```
- Don't import the non-Mutiny `io.vertx.core.*` types in Mutiny code. The signatures don't compose.
## Common operators
- `.map(fn)` — synchronous transform.
- `.onItem().transformToUni(fn)` — async transform returning a `Uni`. Equivalent to `flatMap`.
- `.onFailure().recoverWithItem(default)` — fallback on error.
- `.onFailure().retry().atMost(3)` — retry the upstream up to N times.
- `.ifNoItem().after(Duration.ofSeconds(5)).fail()` — timeout.
## Combining Unis
```java
Uni<Result> combined = Uni.combine().all().unis(uniA, uniB)
.with(Result::new);
```
- `combine().all()` for "wait for all". `combine().any()` for "first that completes".
- For collections: `Uni.combine().all().unis(listOfUnis).combinedWith(...)`.
## Subscribers
- Mutiny is **lazy**. The pipeline doesn't run until subscribed.
- In Vert.x Web with Mutiny: return `Uni<T>` from a handler — the framework subscribes for you.
- Manual: `uni.subscribe().with(item -> ..., failure -> ...)`.
## Backpressure (Multi)
- `Multi.createFrom().items(...)` for known finite streams.
- `Multi.createFrom().publisher(reactivePublisher)` for streams from another reactive lib.
- For backpressure: `.onOverflow().buffer(size)`, `.onOverflow().drop()`, etc. Choose based on what loss is acceptable.
## Error handling
- `onFailure()` selectors: `.onFailure(IOException.class).recoverWithUni(fallback)`.
- Always handle failures explicitly. Unhandled failures in `Uni` log a warning and disappear.
- Don't catch in the underlying lambda — let Mutiny carry the failure.
## Concurrency
- Mutiny respects the Vert.x event loop. Operators don't switch threads unless you ask.
- `.runSubscriptionOn(executor)` to subscribe on a specific executor.
- For blocking work inside a Uni chain: `.onItem().transformToUni(item -> Uni.createFrom().item(() -> blockingCall(item)).runSubscriptionOn(workerPool))`.
## Don't
- Don't mix Mutiny with raw Vert.x callbacks in the same chain. Convert at the boundary.
- Don't subscribe inside a handler — return the `Uni`.
- Don't `await().atMost(...)` on Unis in production code. That's blocking, defeating the purpose.
- Don't log inside `.map` lambdas — switch to `.invoke(item -> log.info(...))` for side-effect-only operators.
Other Vert.x templates
Modern Vert.x Rules
Vert.x 4+ defaults: verticles, event loop discipline, and the golden rule.
Vert.x Web Routing
Vert.x Web router, sub-routers, body handler, validation, and error handling.
Vert.x Event Bus
Event bus messaging — point-to-point, pub/sub, request-reply, codecs, clustering.
Vert.x + Reactive Postgres
Vertx-pg-client for fully reactive Postgres access — pooling, prepared queries, transactions.