Modern Vert.x Rules
Vert.x 4+ defaults: verticles, event loop discipline, and the golden rule.
# CLAUDE.md — Modern Vert.x
## Mental model
- Vert.x is an **event-driven, non-blocking** toolkit. Code runs on a small pool of event-loop threads.
- The **golden rule**: never block an event loop. If you need to block, use `executeBlocking` to run on a worker pool.
- Code that violates the rule is the #1 source of Vert.x bugs. Profile early and often.
## Verticles
- A **Verticle** is a unit of deployment. Like a fiber/actor with its own lifecycle.
- Two flavors:
- Standard: runs on the event loop. Default for HTTP servers, clients.
- Worker: runs on a worker pool. Use for blocking work.
- Deploy with `vertx.deployVerticle(MyVerticle.class.getName(), options)`.
## Async patterns
Three styles in modern Vert.x — pick **one** per project:
1. **Callback style** — original API. Avoid in new code; nesting gets painful.
2. **Future-based** — `Future<T>` with `.compose`, `.map`, `.recover`. Cleaner than callbacks.
3. **Mutiny** — `Uni<T>` / `Multi<T>`. Reactive Streams compatible. The recommended style for new code, especially with Quarkus.
```java
// Future style
client.get("/users").send()
.compose(resp -> validate(resp))
.map(body -> body.toJsonObject())
.onSuccess(json -> log.info(json))
.onFailure(err -> log.error("failed", err));
```
## Event loop discipline
- Never call `Thread.sleep`, `Object.wait`, or any blocking I/O on an event loop thread.
- Vert.x detects long-running event-loop callbacks and warns: `Thread Thread[vert.x-eventloop-thread-0] has been blocked for X ms`.
- For genuinely blocking work, use:
```java
vertx.executeBlocking(() -> doExpensiveThing(), false, ar -> { ... });
```
- The `ordered=false` flag means Vert.x can run blocking calls in parallel.
## Configuration
- `JsonObject` config passed to verticles via `DeploymentOptions.setConfig(...)`.
- For env-driven config, use Vert.x Config (`io.vertx:vertx-config`) with sources: env, files, HTTP.
- Parse to a typed POJO at boot — don't pass `JsonObject` through your code.
## Logging
- Vert.x uses **java.util.logging** by default. Switch to SLF4J via system property: `-Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory`.
- Always configure structured JSON logs in production.
## Threading model
- Default: 2 × CPU event loops. Tune with `VertxOptions.setEventLoopPoolSize(...)`.
- Worker pool: 20 threads default. For heavy blocking work, increase or split into custom worker executors.
- Each verticle is pinned to one event loop. Don't share state across verticles via static fields — use the event bus.
## Don't
- Don't `Thread.sleep`. Use `vertx.setTimer(ms, ...)`.
- Don't hold mutable state across `.compose` boundaries. The continuation may run on a different thread.
- Don't catch and ignore Future failures. Always handle them.
- Don't block the event loop for any reason. If unsure, profile.
Other Vert.x templates
Vert.x Web Routing
Vert.x Web router, sub-routers, body handler, validation, and error handling.
Vert.x with Mutiny (Reactive)
Mutiny Uni/Multi over the callback API — composable reactive workflows.
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.