Module 13: Advanced Async Patterns
Cross-turn handlers and advanced reactive patterns.What You’ll Learn
- Cross-turn message handlers for logging and metrics
- Error handling patterns in reactive streams
- Resource management for long-lived clients
- When to use advanced patterns vs simple TurnSpec
Prerequisites
This module assumes you’ve completed Module 04: ClaudeAsyncClient and understand the TurnSpec pattern.Cross-Turn Message Handlers
Register handlers that receive messages across all conversation turns:Key Reactive Operators
| Operator | Purpose |
|---|---|
doOnNext | Side effects for each element |
doOnSuccess | Side effect for Mono result |
flatMap | Chain to next operation (enables multi-turn) |
filter | Select specific message types |
doOnError | Handle errors |
subscribe() | Start the stream (nothing happens until you subscribe) |
Error Handling
Use Case: Spring WebFlux SSE Endpoint
One common use case is streaming responses via Server-Sent Events:When to Use ClaudeAsyncClient
| Scenario | Recommendation |
|---|---|
| Reactive web application | ClaudeAsyncClient |
| SSE streaming to browser | ClaudeAsyncClient |
| High-concurrency server | ClaudeAsyncClient |
| CLI tool or script | ClaudeSyncClient |
| Traditional blocking web app | ClaudeSyncClient |
| Simpler debugging needs | ClaudeSyncClient |
Tradeoffs and Limitations
Complexity: Reactive programming has a steeper learning curve. Stack traces are harder to read, and debugging requires understanding the reactive execution model. Error handling: Errors propagate differently in reactive streams. Forgetting to handle errors in the reactive chain can cause silent failures. Blocking operations: Mixing blocking calls (e.g., JDBC) with reactive streams defeats the purpose and can cause thread starvation. Use reactive-compatible libraries throughout. Testing: Unit testing reactive code requiresStepVerifier or similar utilities. Standard JUnit assertions don’t work directly with Flux and Mono.
Resource management: The async client is typically a long-lived managed bean (not created per-request). Close it during application shutdown, not after each request.