liveBook · Manning

Multi

As explained in Quarkus in Action

Multi is a Mutiny asynchronous type that emits zero or more items followed by a completion or failure event.

Multi is SmallRye Mutiny’s type for an asynchronous stream of zero or more items. A stream may keep producing items indefinitely; when it ends, it emits a completion event. Use Multi where one result is not enough—for example, for streamed gRPC messages or multiple results from reactive data access. Uni represents a single asynchronous result instead. section 4.8.1 section 7.7 section 8.2.2

A Multi becomes useful when its pipeline is subscribed to. Fluent stages run as items arrive: they can transform items, observe them without changing them, or filter them out. Subscription starts the pipeline; constructing it alone does not. Completion can have its own callback. section 8.2.2

Transform and filter a stream

Create a Multi from "a", "b", and "c"; uppercase each item, append " item", and filter out the result beginning with "B". The subscriber receives "A item" and "C item", followed by the completion callback. Intermediate observation still sees all three uppercase items. section 8.2.2

Listing 8.1 An example use of the Mutiny API
Multi.createFrom().items("a", "b", "c")
    .onItem()
        .transform(String::toUpperCase)
    .onItem()
        .invoke(s -> System.out.println("Intermediate stage " + s))
    .onItem()
        .transform(s -> s + " item")
    .filter(s -> !s.startsWith("B"))
    .onCompletion()
        .invoke(() -> System.out.println("Stream completed"))
    .subscribe()
        .with(s -> System.out.println("Subscriber received " + s));

The listing shows how transform, invoke, filter, completion, and subscription fit into one fluent Multi pipeline. section 8.2.2

For bidirectional gRPC streaming, mark both request and response messages with `stream` in the protobuf method. The generated reactive service can then accept `Multi<InsertCarRequest>` and return `Multi<CarResponse>`. Each incoming request is mapped to a car, persisted, and mapped to a response, allowing multiple cars to be added over one connection. section 4.8.1 section 8.4.2

A reactive return type does not make every operation nonblocking. The inventory implementation uses blocking database I/O, so its gRPC method needs `@Blocking` rather than execution on an event-loop thread. Hibernate Reactive and reactive drivers provide a nonblocking data-access alternative. section 8.4.2 section 7.7

Multi can also connect reactive-messaging methods. A producer emits ticks as `Multi<Long>`; a processor maps them to a `Multi<String>` on another channel; a consumer prints the resulting messages. section 9.3.2

How Quarkus in Action covers it

How deep it goes
Works through fluent transformations, filtering, subscription, completion, and a gRPC implementation; does not detail Multi internals.
Examples
Uses a three-item transform-and-filter pipeline, bidirectional car-inventory gRPC calls, and a tick-producing messaging pipeline.
What it assumes
Introduces Uni, Multi, and pipeline subscription while using Java method signatures and protobuf declarations in application examples.
What you can do after
Apply it via SmallRye Mutiny and Quarkus to process item streams, while identifying blocking work that needs `@Blocking`.
How it connects
Connects Multi to Uni, Reactive Streams, gRPC streaming, Hibernate Reactive, and MicroProfile Reactive Messaging.

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.