liveBook · Manning

Asynchronous programming

As explained in Quarkus in Action

Asynchronous execution is computation in which an operation completes independently of the caller and reports its result or failure later.

Asynchronous programming lets an operation finish independently of its caller and report a result or failure later. A service can keep processing requests instead of holding a thread idle while a remote call or database operation completes. This can improve responsiveness and allow the same resources to handle more work. section 8.0

In distributed applications, asynchronous message passing also reduces the need for both services to be available at the same moment. A sender places a message on a channel and continues working. If the receiving service is unavailable, a channel with buffering can retain messages until it can process them. This shifts delivery concerns into the channel; it does not make failures disappear. Messages, including errors, help keep services loosely coupled, while backpressure lets a consumer control the load it receives. section 9.3.1 section 9.2

Figure 9.4 The asynchronous communication failure propagation in microservices
figure

The failure-propagation diagram illustrates messages waiting in channels while receiving services are unavailable. section 9.3.1

For a Quarkus microservice, MicroProfile Reactive Messaging provides channels between producers and consumers. Methods in CDI beans use @Incoming and @Outgoing; an Emitter can send from a method that is not itself a messaging method. SmallRye Reactive Messaging supplies the Quarkus implementation and connectors for remote brokers such as Kafka and RabbitMQ. Messaging does not require every handler to use reactive code: blocking APIs can also be used in Quarkus messaging integrations. section 9.10 section 9.4

Send an invoice after a reservation

Add the quarkus-messaging extension, then inject @Channel("invoices") Emitter<Invoice> into the reservation endpoint. After persisting a reservation, send an Invoice containing the reservation and its computed price. A local stub consumes it with @Incoming("invoices") before the channel is connected to a separate Billing service. Emitter.send returns a CompletionStage that can report failure; a MutinyEmitter alternative returns a Uni on which a failure handler can be attached. The billing request can run asynchronously because an unpaid reservation can be canceled later. section 9.4

For communication between services, attach a connector rather than treating an in-process channel as a remote link. The rental application uses Kafka between Rental and Billing and RabbitMQ between Reservation and Billing. These examples demonstrate the messaging API, not Kafka internals or a universal delivery guarantee. section 9.6 section 9.9

How Quarkus in Action covers it

How deep it goes
Works through Quarkus messaging channels, emitters, failure handling, and broker connectors, but does not cover Kafka internals.
Examples
Uses an invoice channel, a Billing stub, a reservation endpoint, and Kafka and RabbitMQ service links.
What it assumes
Builds on reactive programming and Mutiny while introducing messaging channels and connectors for interservice communication.
What you can do after
Build it from scratch with Quarkus messaging channels and connectors, and handle an emitter's reported failure.
How it connects
Connects reactive systems, nonblocking I/O, backpressure, reactive streams, and MicroProfile Reactive Messaging.

Also explained in

Compare how 28 books explain asynchronous programming →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Quarkus in Action. The section links point to the parts of the book it draws on.