Class PipelineBuilder<T,C>
- Type Parameters:
T- payload the pipeline is entered withC- payload the step declared most recently produces
mq.pipeline("fulfilment", Order.class)
.step("validate", Order.class, new ValidateOrder())
.step("enrich", Enriched.class, new EnrichOrder())
.withRetry(RetryPolicy.exponential(5, Duration.ofSeconds(2), Duration.ofMinutes(1)))
.concurrency(10)
.step("dispatch", Void.class, new DispatchOrder())
.build();
The type parameter moves with each step, so a Step<Order, Enriched> cannot be put
where one producing an Order belongs. That is the reason this is a builder rather than
a list of names: a typo in a string is found in production, and a type error is found by the
compiler.
The settings after a step apply to that step. They read as a chain because
steps fail differently, and giving a pipeline one retry policy would mean giving the step that
should never retry the same treatment as the one that always should.
-
Method Summary
Modifier and TypeMethodDescriptionbuild()Declares the topology and starts a consumer group per step.concurrency(int howMany) describedAs(String text) Describes the most recently declared step, for the humans reading the logs.Publishes the most recent step's output in a named format.idempotent(IdempotencyStore store) Handles each message at most once at the most recently declared step.prefetch(int prefetch) <O> PipelineBuilder<T, O> Adds a step to the end of the chain.toString()withRetry(RetryPolicy policy) Retries the most recently declared step on a schedule, never in a sleeping handler: the engine holds a short wait and the broker's queues hold a long one.
-
Method Details
-
step
Adds a step to the end of the chain.- Type Parameters:
O- produced type- Parameters:
stepName- how the step is named on the wire and in the routing slipproduces- what this step's handler returns, which the next step receiveshandler- the work- Returns:
- a builder whose next step receives
O
-
describedAs
Describes the most recently declared step, for the humans reading the logs..step("reserve", Reservation.class, this::reserve) .describedAs("hold stock for 15 minutes so payment cannot oversell")Separate from the step name rather than folded into it, because the name has a job: it is the routing key and the routing slip entry, so it is restricted to letters, digits, dashes and dots and cannot hold a sentence. Changing a name to make it more readable changes the wire format and orphans messages already in flight; changing a description changes a log line.
- Parameters:
text- what this step is for, in a sentence- Returns:
- this builder
-
withRetry
Retries the most recently declared step on a schedule, never in a sleeping handler: the engine holds a short wait and the broker's queues hold a long one.- Parameters:
policy- the schedule- Returns:
- this builder
-
idempotent
Handles each message at most once at the most recently declared step.Worth configuring on any step whose work would matter twice. Each hop is at-least-once, so a step sees a message again whenever a publish succeeded and its acknowledgement did not.
- Parameters:
store- where handled identifiers are remembered- Returns:
- this builder
-
concurrency
- Parameters:
howMany- consumers to run for the most recently declared step. This is how a slow step is given more capacity without touching its neighbours- Returns:
- this builder
-
prefetch
- Parameters:
prefetch- how many messages each consumer of the most recent step may hold- Returns:
- this builder
-
encodedAs
Publishes the most recent step's output in a named format.A format change is not a step. Making it one would add a queue, a publish, a confirm and a consumer whose entire job is to deserialize and reserialize the same object — a network round trip to change nothing but the encoding.
- Parameters:
codec- the format for this step's output- Returns:
- this builder
-
build
Declares the topology and starts a consumer group per step.- Returns:
- the running pipeline
-
toString
-