Hard20 minDistributed Systems
UpdatedAug 6, 2026
Edit

Service Bus: Ordered Per-Order Work

Question Variations

  • "Why is a session ID not a global ordering guarantee?"
  • "How would you scale session-enabled consumers?"
  • "What happens if a receiver loses its session lock?"

Why This Is Asked

Several order events may arrive quickly, but cancellation must not run before creation for the same order. This tests whether a candidate can use Service Bus sessions to serialize related work while keeping different orders parallel.

Key Concepts

  • Session ID: Assign the order ID so related messages are grouped into one session.
  • Exclusive session lock: One receiver processes a given session at a time, preserving its delivery sequence.
  • Parallelism: Different sessions can be handled concurrently by separate processors.
  • Idempotency: Lock expiry and settlement failures still allow redelivery, so sessions are not exactly-once processing.

Question Variations

  • “Why is a session ID not a global ordering guarantee?”
  • “How would you scale session-enabled consumers?”
  • “What happens if a receiver loses its session lock?”

Answers by Technology

+ Add Variant
Azure Service BusImprove this answer ✏️

Expected Answer

Set sessionId to the order ID on every event in that order’s workflow. Service Bus grants one receiver an exclusive lock for a session, so that receiver processes the order’s events in sequence. Different order sessions can be accepted by different workers at the same time, preserving parallelism. Keep session work bounded and renew the lock only when genuine processing needs more time. If the receiver loses the lock or crashes before completion, messages can be delivered again, so use idempotent state transitions and do not mistake sessions for exactly-once processing. A session enforces ordering only within the same session ID; unrelated orders have no global order.

Why It Matters

Without session-scoped ordering, cancellation can race ahead of creation. A single global queue would avoid that race but unnecessarily serializes every order and caps throughput.

Example Code

await sender.sendMessages({ body: event, messageId: event.id, sessionId: event.orderId });
const receiver = client.acceptSession("orders", event.orderId);
const message = await receiver.receiveMessages(1);
await applyOrderEvent(message[0].body);
await receiver.completeMessage(message[0]);

Common Mistakes

  • Using a random session ID: Related events no longer share ordered processing.
  • Holding a session lock during slow external work: Lock loss causes redelivery and duplicate external effects.

Follow-up Questions

  • Does a session order all messages in a queue? (Answer: No; it orders messages sharing one session ID.)
  • How is throughput scaled? (Answer: Run multiple processors that each accept different sessions.)

Related Questions

References