Message and Headers
Message
A Message (package io.pipelite.core.exchange.internal) is the container for the application
payload - one for the input of the Exchange, and, once produced, one for its output. It carries
the payload itself, its type and a correlation id, nothing else - it has no metadata of its own,
that role belongs to Headers, which lives on the Exchange rather than on either Message (see
below).
A Processor never needs to hold a Message reference directly: exchange.getInputPayload() /
getInputPayloadAs(Class) read the input message’s payload, and exchange.setOutputPayload(Object)
writes the output message’s payload - see Exchange.
| The id of a message changes from one step of the flow to the next, and is not the same when the application restarts and gives a message back: it is not a key to hand to an external system. For that, see the idempotency key of the exchange. |
Headers
Headers are string key-value pairs that live on the Exchange itself, not on the Message -
there is a single set of headers per exchange, and neither its input nor its output Message
knows anything about them.
Read
Headers headers = exchange.getHeaders();
// Optional read
Optional<String> value = headers.tryGetHeader("x-request-id");
// Read with expectation (throws NoSuchElementException if absent)
String value = headers.expectHeader("x-request-id");
// Typed read
Optional<Integer> n = headers.tryGetHeaderAs("retry-count", Integer.class);
// Presence check
boolean present = headers.hasHeader("x-request-id");
Write
headers.putHeader("x-correlation-id", "xyz-789");
headers.removeHeader("x-temp");
Headers survive across the whole flow: whenever an Exchange advances to the next node, the
framework carries a copy of the current headers into the new Exchange - a header set at any
step is still visible in every step downstream.
Headers vs. payload
Both travel through the flow together, but for different reasons:
-
Use headers for information about the message that a downstream step needs to decide what to do, without caring what the message actually contains - e.g. a
priorityorregionheader that afilterortoRoute(…)uses to send an order down a different path depending on where it came from, regardless of what is inside the order itself. They are cheap to read (Headers['name']) and are exactly whatfilterandtoRoute(…)are built around (see Expressions). -
Use the payload for the actual content being processed - e.g. the
Orderobject itself, with its line items and total, that eachProcessorreads, transforms or replaces. It is what the pipeline exists to move and change; headers are metadata riding along with it, not a second place to put application data.
A simple test: if a value is something you would filter or route on without touching the business object, it belongs in a header; if it is the data your processors' logic actually reads or produces, it belongs in the payload.