Message Queues
We do not have to build the list of orders ourselves. There is ready-made software that holds work from one program until another program takes it. One kind is the message queue. Let’s name its parts.
Message
A message is the data that one program leaves for another to handle. Order 93 is a message:
{
"orderId": "93",
"shopId": "mugshop",
"shopperId": "12",
"cartId": "80",
"idempotencyKey": "b71e"
}
The message carries the IDs that the program placing the order needs. The order itself is already saved with the status PROCESSING.
Message queue
A message queue is a list that holds messages until a program takes them. We call the list of orders the order queue. New orders join one end of the queue, and the program that places orders takes them from the other end:
graph TD
C[Commerce service: handles requests] -->|order 95| Q
subgraph Q[Order queue]
direction LR
O94[order 94] ~~~ O93[order 93] ~~~ O92[order 92]
end
Q -->|order 91| W[Commerce service: places orders]
Broker
The broker, or message broker, is the software that keeps the queues. Here, it keeps the order queue:
graph TD
C[Commerce service: handles requests] -->|order 95| B
subgraph B[Broker]
subgraph Q[Order queue]
direction LR
O94[order 94] ~~~ O93[order 93] ~~~ O92[order 92]
end
end
B -->|order 91| W[Commerce service: places orders]
Producer and consumer
The producer puts messages on a queue. Here, it is the part of the commerce service that handles placeOrder requests. In the diagram, it sends order 95 to the broker.
The consumer takes messages from a queue and handles them. Here, it is the part of the commerce service that places the orders. In the diagram, it takes order 91 from the broker.
The order queue
Here is the commerce service with the order queue inside it:
graph TD
S[Storefront] -->|placeOrder| H
subgraph C[Commerce service]
H[Handles requests] -->|order 93| MQ[Message queue]
MQ -->|order 93| W[Places orders]
end
H -->|save order 93: PROCESSING| DB[("Primary of Mugshop's shard")]
W -->|place order 93| DB
Both parts of the commerce service write to the primary. The part that handles requests saves each new order with the status PROCESSING. The part that places orders runs the transaction.
Tracing order 93
Here is order 93 again, from the request to the payment, with the parts named:
sequenceDiagram
participant S as Storefront
participant C as Producer: handles requests
participant B as Broker: order queue
participant W as Consumer: places orders
participant Pay as Payment service
participant P as Primary
S->>C: placeOrder
C->>P: Save order 93: PROCESSING
C->>B: Message: order 93
B->>B: Save order 93 in the order queue
B-->>C: Saved
C-->>S: Order 93, processing
Note over B: Order 93 waits behind earlier messages
W->>B: Next message
B-->>W: Order 93
W->>P: Run the transaction
W->>Pay: Take the payment
W->>P: Set order 93: PLACED
A consumer that is waiting gets a new message as soon as the message reaches the queue. Brokers do this in one of two ways. In the first, the consumer keeps a connection open to the broker, and the broker sends the next message over it. In the second, the consumer sends a request for messages, and the broker holds the request until a message arrives. This second way is long polling, the same technique we used for chat.