Lanes
One subscription hands its messages over one at a time; workers(n, by_key) spreads them over
lanes keyed by the nats-partition-key header.
The diagram as text
- The subscription a Core subject or a pull consumer → NatsSubscriber stream one message at a time: delivered
- NatsSubscriber stream one message at a time → workers(2, by_key) lane = hash of nats-partition-key: one at a time
- workers(2, by_key) lane = hash of nats-partition-key → Lane 1 key a, in order
- workers(2, by_key) lane = hash of nats-partition-key → Lane 2 key b, in order
- A message without the header has no key: such messages rotate over the lanes
- Across processes: a queue group or a shared durable hands each message to one member
Without workers, one loop runs the handler for each message in turn. The subscription's order is
kept, and nothing runs side by side.
workers(n, by_key) runs n lanes. A message goes to the lane its key hashes to, and a lane runs
its messages in order. NATS has no partition of its own, so the key is the
nats-partition-key header, which the sender sets. Messages
of one key keep their order, and different keys run side by side.
Across processes the server shares the work. A queue group
hands each Core message to one member, in the order the server picks. Subscriptions that bind one
durable consumer take each JetStream message in turn.
max_ack_pending bounds how many messages of a
consumer wait for an answer at once, across all its members.
A batch handler takes up to the size the mount site
names. On JetStream one batch is one fetch, closed early by pull_expires. On Core the batch is
assembled on the client and closes at the size or 10 milliseconds after its first message.