Classic design · Mid
E-commerce: catalog, cart, and checkout
Classic interview design. Key points: reservations and concurrency.
Short answer
Classic interview design. Key points: reservations and concurrency. The classic e-commerce exercise asks for a product catalog, a cart, and a checkout. This case focuses on checkout, the moment when a single customer action has to change three sets of data: the order, the inventory, and the payment. Catalog and cart appear only as context.
01 · CONTEXT
One click, three data owners
The classic e-commerce exercise asks for a product catalog, a cart, and a checkout. This case focuses on checkout, the moment when a single customer action has to change three sets of data: the order, the inventory, and the payment. Catalog and cart appear only as context.
Architectures of microservices usually give each service a dedicated database. When orders and customers live in the databases of different services, the application cannot use a simple local ACID transaction. The source illustrates the problem with an online store in which the customer has a credit limit.
02 · STARTING POINT
One database, one transaction
With a single database, life is simple. Within a single service, transactions follow ACID principles because they operate on one database, and atomicity means that all operations succeed or none do. Writing the order and decrementing inventory in the same transaction therefore guarantees that both happen or neither does.
The customer confirms the purchase; the request passes through the store's API and reaches the application.
The application opens a local transaction on the single database.
Within the same transaction it writes the order and decrements inventory, and both changes are committed together.
If something fails midway, neither change takes effect and the database rolls everything back.
03 · SPLITTING
When each service has its own database
Splitting into services brings gains that Microsoft's documentation lists: each service encapsulates its data and failures in one service stay isolated from the others. The price is that guarantees like ACID do not apply directly across several independently managed databases.
The customer confirms the purchase and the API forwards the order to the orders service.
The orders service writes the order to its own database, in a local transaction.
Next, the orders service calls the inventory service, which decrements the quantity in its database.
Then it calls the payments service and, in this scenario, the charge does not complete.
Order and inventory have already been committed in their databases, and there is no automatic rollback that spans the three services: what was done has to be undone explicitly.
04 · SAGA
Local steps and compensations
The classic answer is the saga: a sequence of local transactions coordinated reliably. If a step fails by violating a business rule, the changes of the already completed steps are undone by compensating transactions.
There are two ways to coordinate the saga. In choreography, each local transaction publishes domain events that trigger local transactions in other services. In orchestration, an orchestrator tells the participants which local transactions to run.
| Aspecto | Coreografia | Orchestration |
|---|---|---|
| How it coordinates | Each service publishes events that trigger the other services' steps | An orchestrator tells the participants what to run |
| When it fits | Simple flows with few services | Complex flows or ones that gain new services |
| Weak point | The flow can get confusing as steps are added | The orchestrator is a point of failure, since it manages the whole flow |
The source describes the order like this: the orders service receives POST /orders and creates the order in PENDING state; the customers service tries to reserve credit; and the orders service's event handler approves or rejects the order.
The orders service receives the purchase and creates the order in pending state; in the same local transaction it writes the message that needs to be sent.
A separate process reads the outbox and sends the message to the broker.
The inventory service receives the message and tries to reserve the items in a local transaction, just as the source's example tries to reserve credit.
With the reservation made, the payments service attempts the charge; in this scenario it is declined for insufficient funds, an expected failure and not an unexpected error.
The failure reaches the inventory service, which runs the compensating transaction and releases the reservation made earlier.
Finally the orders service receives the result and rejects the order, instead of approving it.
The saga has costs. There is no automatic rollback, so the developer has to design the compensating transactions that undo what was done. And there is no isolation between concurrent sagas: careful analysis is needed to choose and implement countermeasures. In addition, compensations may not succeed and leave the system inconsistent.
05 · RELIABLE MESSAGING
Write and publish without losing anything
For the saga to work, the service must update the database and send the message atomically, otherwise inconsistencies appear. A distributed transaction spanning the database and the broker is not viable. Without one, sending the message in the middle of the transaction gives no guarantee that it will be committed, and sending after the commit does not guarantee the service won't crash before sending.
The way out is the transactional outbox: the service writes the message to the database, in the same transaction that updates the business entities, and a separate process sends it to the message broker.
This relay can publish the same message more than once, for example if it crashes after publishing and before recording that it published. So the consumer must be idempotente, for example by recording the identifiers of the messages already processed.
Since the saga is an asynchronous flow, whoever started the purchase through a synchronous request has to find out the result later. One of the source's options is to return the order identifier and let the client poll the state periodically.
06 · PAYMENT
Charge once, even with failures
Payment is the step where an error costs the most. The goal described by Shopify is that the charge happens exactly once despite request retries. The idempotency key finds the steps the attempt has already completed, and ensures that a single request is sent to the financial partner.
The orders service requests the charge by sending a unique key for the attempt.
The payments service records the attempt in the local database, one of the steps the key allows it to find again.
The service calls the financial partner with low timeouts so it does not wait indefinitely.
If the call fails due to the network, the request can be repeated with the same key, and the partner receives a single request.
A reconciliation job compares the local records with the partner's and, when there is a discrepancy, records the anomaly in the database.
Within the saga, the Azure Architecture Center calls the point of no return the pivot transaction. After it come retryable, idempotent transactions, which help the saga reach the final state even with transient failures.
07 · PEAK LOAD AND ISOLATION
Protect checkout and close the gaps
Under peak load, Shopify uses programmable load balancers to limit the number of simultaneous checkouts. If more buyers want to pay than capacity allows, they wait in a queue before paying.
Isolation remains. There is no isolation between concurrent sagas, and Microsoft's documentation lists anomalies such as lost updates and dirty reads, the latter when one saga reads data another has modified without finishing. One of the countermeasures is to re-read the values before updating.
Frequently asked questions
What is E-commerce: catalog, cart, and checkout?
Classic interview design. Key points: reservations and concurrency.
What does the E-commerce: catalog, cart, and checkout design cover?
It is organized in these sections: One click, three data owners, One database, one transaction, When each service has its own database, Local steps and compensations, Write and publish without losing anything, and Charge once, even with failures.
How long is E-commerce: catalog, cart, and checkout and what level is it?
It takes about 14 minutes to read and is rated Mid level.
Now design it yourself
Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.