How do you design the inventory management component?
Fast recall
Quick revision
Core answer
Understanding of concurrency control in inventory systems, the difference between catalog data and stock data, the two-phase commit pattern for reservations, and awareness that stock operations need atomicity to prevent race conditions
Storing stock count directly in Product table without atomic operations, checking availability without reserving, leading to overselling, or not handling reservation expiry when users abandon carts, causing stock to be locked indefinitely
Mention optimistic locking with version fields to avoid database locks at scale, distributed inventory across warehouses with smart allocation, handling reservation timeouts, and eventual consistency trade-offs when displaying stock levels to users
Interview-ready guide
Interview answer
The core challenge in inventory is overselling — two customers buying the last unit at the same moment. So I wouldn't model stock as a single number that I decrement at payment time, because both shoppers would pass the availability check before either decrements. Instead I split stock into available and reserved.
At checkout, I reserve atomically: move the quantity from available to reserved in one indivisible operation. To make that safe under concurrency, I'd use optimistic locking with a version field — the caller reads the current version, and the reserve only succeeds if the version hasn't changed. If another transaction got in first, the version won't match, the reserve returns false, and the caller retries with fresh data. Alternatively a database row-level lock achieves the same thing. Either way, only one of the two racing shoppers wins the last unit.
Then the reserved stock has its own lifecycle. On payment success, I confirm — the reserved quantity is consumed. On payment failure or if the cart expires, I release — the quantity goes back to available. That release step is essential; without it, abandoned carts would lock inventory forever and the item would look out of stock when it isn't. One refinement I'd mention: reserve at checkout, not when the item is added to the cart, because reserving too early makes popular items disappear from everyone else's view while one person dithers.
How do you design the inventory management component
Direct Answer
Inventory management requires a separate Inventory entity tracking availableStock and reservedStock for each product. When a user adds items to cart and proceeds to checkout, the system calls reserveStock atomically (using database row-level locking or optimistic locking with a version field) to decrement available and increment reserved. This prevents overselling when multiple users buy simultaneously. On successful payment, convert reserved to sold (decrement reserved). On order cancellation or timeout, return reserved stock to available. For multi-warehouse setups, Inventory has a warehouseId field, and allocation algorithms pick the optimal warehouse based on customer location.
Deep Dive & Architecture
Stock is governed by an invariant
For one product and warehouse, the quantities must never become negative, and committed plus reserved stock must not exceed the stock received. The Inventory aggregate owns these numbers so checkout code cannot alter them independently.
Reservation separates intent from sale
Checkout requests reserve(productId, quantity, reservationId). The operation atomically reduces available stock and increases reserved stock. Payment success confirms the reservation and consumes it; cancellation or expiry releases it. The reservation id makes retries safe and gives a cleanup job something specific to expire.
Concurrency is tested with the last unit
Suppose available stock is one and two buyers reserve it at the same time. An optimistic version check or a database update such as UPDATE ... WHERE available >= 1 lets exactly one request change the row. The other receives an out-of-stock result instead of creating negative inventory. In a multi-warehouse system, allocation chooses a warehouse first, but the selected warehouse still performs the same atomic reservation locally.
Code Example
class Inventory {
private final String productId;
private int available;
private int reserved;
private int version; // optimistic lock token
// returns false if not enough stock OR a concurrent update bumped the version
synchronized boolean reserve(int qty, int expectedVersion) {
if (version != expectedVersion) return false; // someone else changed it -> retry
if (qty > available) return false; // would oversell
available -= qty;
reserved += qty;
version++;
return true;
}
synchronized void confirm(int qty) { reserved -= qty; } // payment succeeded
synchronized void release(int qty) { reserved -= qty; available += qty; } // failed/expired
}
Reserve on checkout, confirm on payment, release on failure — the version field detects concurrent edits.
Common Mistakes & Pitfalls
- Single stock count, decrement on payment — two buyers both pass the check and oversell.
- No reservation release — abandoned carts lock stock forever.
- Ignoring concurrency entirely — say how you make reserve atomic (lock or version).
- Reserving on add-to-cart — too early; reserve at checkout, or low-stock items vanish from everyone's view.
Check your understanding
Answer these without looking back at the article.
- How do you design the product review and rating system?
- Design an online shopping system like Amazon. What are the core classes?
- How do you design the order state machine in the shopping system?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.