A web request can stall while a service is busy, offline, or slow to respond. With asynchronous messaging, the client sends a message to a queue instead of keeping a direct connection open. A handler receives and processes the message later. The client need not wait for the work to finish. section 21.1
Figure 21.8 Asynchronous processing uses a message handler as well as an event publisher.
The diagram separates the event publisher, message queue, and handler—the three parts needed to follow an asynchronous save. section 21.3
Save a to-do item through NATS
Run the queue with `docker compose up -d message-queue`, then start the web app and database with `docker compose up -d todo-web todo-db`. Adding an item publishes a new-item event rather than writing directly to SQL. Start the subscriber with `docker compose up -d save-handler` and check `docker logs todo-list-save-handler-1` to see it handle new events. Refresh the list if an item does not appear immediately: the page can load before the handler finishes saving it. section 21.2 section 21.3
Once events are flowing, handlers and publishers can change independently:
- Scale save handlers with `docker compose up -d --scale save-handler=3` to share incoming work while limiting pressure on SQL connections. section 21.3
- Add an audit handler to consume the same events, or add a REST API that publishes them, without changing the existing components. section 21.4
Publish-subscribe allows zero or more subscribers, but a publisher does not know who handled an event or when. If the client needs an answer, request-response messaging sends a reply through the queue. Queue choice also matters: NATS stores messages in memory, while RabbitMQ and Kafka offer persistent messaging. Choose the pattern and queue to match the work rather than assuming every message exchange has the same delivery needs. section 21.2 section 21.5



























