Sequential Convoy
Sequential Convoy preserves message order within groups (by a key like entity ID) while processing different groups in parallel, using sessions, FIFO groups, or partitions. It delivers per-entity ordering plus concurrency, bounded by the number of groups.
The Sequential Convoy pattern lets a system process a set of related messages in the order they were sent, while still processing unrelated messages concurrently. It reconciles two normally conflicting goals: strict ordering and parallel throughput.
The problem arises with Competing Consumers, which maximizes throughput but does not guarantee order, since any consumer may grab any message. Yet some messages must be handled in sequence, for example all events for the same order or account.
How It Works
Messages are grouped by a key that defines a convoy, such as customer ID, order ID, or account number. The messaging system guarantees that messages within the same group are delivered to a single consumer in order, while different groups can be handled by different consumers in parallel. Brokers implement this with session-based or partition-based ordering: Azure Service Bus sessions, Amazon SQS FIFO message group IDs, and Apache Kafka partition keys.
A consumer locks a group (session), processes its messages in order, and releases it. Other consumers process other groups simultaneously. Throughput scales with the number of groups while order is preserved within each group.
When to Use It
Use it when ordering matters per entity but not globally: applying a sequence of state changes to an account, processing events for a specific device, or handling steps of a per-customer workflow. It is the standard way to get both ordering and scale.
Avoid it when no ordering is required (plain Competing Consumers is simpler) or when strict global ordering across all messages is mandatory, which serializes everything.
Trade-offs
Parallelism is limited by the number of active groups; if one group is very hot, its single consumer becomes a bottleneck. A stuck or slow message in a group blocks the rest of that group until resolved, so failure handling and dead-lettering must be careful to avoid head-of-line blocking. Choosing the grouping key well is essential for balanced load.
The benefit is correct per-entity ordering with concurrency across entities.
Related Patterns
It extends Competing Consumers with ordering guarantees and can be combined with Priority Queue and Pipes and Filters. It is the messaging counterpart of partitioned, key-ordered stream processing.
Example
A banking service processes account events. Using Service Bus sessions keyed by account ID, all events for account A go to one consumer in order, while events for accounts B and C are processed by other consumers at the same time. A deposit then a withdrawal for account A always apply in the right sequence, yet the system still handles thousands of accounts concurrently.