MicroProfile Reactive Messaging defines an API for asynchronous message passing. It helps microservices communicate without waiting for responses on blocked threads or coupling services too closely. In Quarkus, SmallRye Reactive Messaging implements the specification; application code can use the same channel API with different messaging brokers. section 9.0 section 9.10
A channel is a named virtual address for messages. Methods on CDI beans produce, consume, or process those messages: @Outgoing names the channel a method produces to, while @Incoming names the channel it consumes from. A processor has both annotations. A channel has one source and one sink; processors connect through additional, uniquely named channels. Message flow builds on Reactive Streams, but Quarkus does not require every messaging method to use reactive types. section 9.3 section 9.3.2 section 9.8.2
Listing 9.1 MicroProfile Reactive Messaging with Mutiny example
@Outgoing("ticks")
public Multi<Long> aFewTicks() {
return Multi.createFrom()
.ticks().every(Duration.ofSeconds(1))
.select().first(5);
}
@Incoming("ticks")
@Outgoing("times")
public Multi<String> processor(Multi<Long> ticks) {
return ticks.map(tick -> Instant.now().toString());
}
@Incoming("times")
public void consumer(String payload) {
System.out.println(payload);
}
A Mutiny Multi produces ticks, a processor transforms them into time strings, and a consumer prints the results; channel names connect the three methods. section 9.3.2
For an imperative entry point, inject an Emitter with @Channel and call send. Its CompletionStage completes when the message is acknowledged, completes exceptionally on a negative acknowledgment, and remains incomplete if no acknowledgment arrives. @Channel can also inject a channel as a Publisher or Mutiny Multi, for example to serve events over an HTTP server-sent-events connection. section 9.3.4
Send an invoice after a reservation
Add the quarkus-messaging extension, inject an Emitter<Invoice> for the invoices channel, and send an invoice when a reservation is persisted. An @Incoming("invoices") method can first act as a local Billing stub. Later, a RabbitMQ connector carries invoices to a separate Billing service, where a processor persists each invoice and forwards it for payment. When forwarding a Message, withPayload preserves its metadata and acknowledgment behavior. section 9.4 section 9.8.2
Connectors bridge application channels to external systems such as RabbitMQ and Kafka; their configuration selects the broker for a channel. Quarkus packages SmallRye connectors as separate extensions and can start broker Dev Services in development mode. For blocking work inside a pipeline, mark the method @Blocking. Asynchronous messages do not themselves trigger Quarkus live reload in Dev mode. section 9.10 section 9.8.2
