We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Messaging Event Systems
Free preview: the first 2 parts of this 7-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Messaging Event Systems
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
You order five items from Amazon. They arrive in one box. But inside, each item has its own label, its own tracking, and needs to go to a different room in your house. Kitchen supplies to the kitchen, books to the shelf, electronics to the office.
The splitter pattern does this for messages. A single message containing multiple items is broken into individual messages, each processed independently. An order with 5 line items becomes 5 separate messages, one per item. A batch file with 10,000 records becomes 10,000 individual messages. A multi-recipient notification becomes one message per recipient.
Why split? Because individual items often need different processing. Line item A ships from warehouse West, line item B ships from warehouse East. Processing them as a single unit forces sequential handling. Splitting them enables parallel processing by different services.
Stripe's payment processing pipeline uses the splitter pattern extensively. When a merchant submits a batch of charges (common in subscription billing), the batch is split into individual charge events. Each charge routes independently through fraud detection, authorization, and settlement. One failed charge doesn't block the other 999 in the batch. Shopify's order fulfillment pipeline splits multi-item orders the same way, with each line item routing to the warehouse that stocks it.
The splitter reads a composite message, iterates over its items, and publishes a separate message for each item:
async function splitOrder(orderMessage: OrderMessage) {
const { orderId, items } = orderMessage;
for (const item of items) {
await queue.publish('line-items', {
orderId, // Correlation ID for later aggregation
itemId: item.id,
sequenceNumber: item.index, // For reassembly order
totalItems: items.length, // So aggregator knows when done
...item
});
}
}
Key metadata to include in each split message:
orderId). Without this, the aggregator cannot group fragments back together.Where splitters live in practice:
| Scenario | Input | Output | Real Example |
|---|---|---|---|
| E-commerce order | Order with N line items | N line-item messages | Shopify: split by warehouse |
| Batch file processing | CSV with 50K rows | 50K individual row messages | Bank: daily transaction file |
| Multi-recipient notification | Notification for 100 users | 100 per-user messages | Slack: channel message to members |
| ETL pipeline | API response with paginated results | Individual records | Stripe: webhook batch to events |
| Subscription billing | Monthly bill run for 10K customers | 10K individual charge events | Stripe Billing batch charges |
The atomicity question. Should the splitter publish all fragments atomically (all or nothing) or one at a time? If the splitter crashes after publishing 3 of 5 fragments, the aggregator will wait forever for fragments 4 and 5. Solutions: use a transactional outbox (write all fragments to a table in one transaction, then a separate process publishes them) or accept partial splits and handle them with a timeout at the aggregator.