# The queue was in order. Your workers were not.

> A customer paid $120 for an item they removed, and Service Bus did nothing wrong.

- **Format:** short video, 12 steps, ~50 seconds
- **Topic:** Why messages are processed out of order when the queue delivered them in order (consumer concurrency, not the broker), and why SessionId is a partition-key decision rather than a FIFO checkbox.
- **Author:** Suthahar Jegatheesan (MSDEVBUILD)
- **Category:** Azure · Azure
- **Tags:** azure, azureservicebus, servicebus, messagesessions, fifo, concurrency, azurefunctions, distributedsystems, systemdesign, microsoftazure, cloudarchitecture, dotnet, az305, msdevbuild
- **Canonical URL:** https://blog.msdevbuild.com/shorts/azure-ordering-concurrency-sessions/

---
## What you'll learn

- That FIFO delivery and FIFO processing are different things, and concurrency is what separates them
- Why SessionId is a partition-key choice, not a yes/no on ordering
- The one setting that silently gives back the race after you enable sessions

## Understand it one step at a time

### 1. Three events, one cart, in order

Add an item, remove it, check out. Published in that sequence, one second apart.

### 2. They were charged for the item they removed

Checkout ran before the removal. The basket still had the headphones in it when the total was taken.

### 3. The queue was never out of order

Service Bus delivered these exactly as they were enqueued. Look further down the pipe.

### 4. You have sixteen workers

maxConcurrentCalls defaults to 16. Sixteen threads pulled three ordered messages and raced them.

### 5. One worker fixes it, and kills throughput

Set concurrency to 1 and the order is perfect. So is the queue depth, climbing all afternoon.

### 6. SessionId = cartId

A session is held by one receiver at a time. In order inside a cart, and still parallel across carts.

### 7. Ordered with respect to what?

This is the real decision. Sessions do not turn ordering on — they choose what it applies to.

### 8. The setting that gives the race back

MaxConcurrentCallsPerSession defaults to 1. Raise it for throughput and you undo everything.

### 9. Turn the other one instead

Total concurrency is sessions multiplied by calls per session. Scale the sessions, never the calls.

### 10. You cannot add sessions later

RequiresSession is fixed when the queue is created. Wanting it afterwards means a new queue.

### 11. And your delayed retry reorders too

Re-enqueue a copy on a backoff and it lands at the back of its session. Ordering and retry pull against each other.

### 12. Ordering is a partition key

Not a checkbox, and not the broker’s fault. It is a decision about what must not overtake what.

---

## The takeaway

**FIFO delivery is not FIFO processing**

The broker keeps the order. Your concurrency is what decides whether you keep it too.
