Inventory Management Service
Design Meesho's in-memory inventory service — stock blocking with a 5-minute hold, auto-release, and safe concurrent checkout at scale.
Design an in-memory inventory service for an e-commerce platform. The core twist: stock isn't deducted the moment a user clicks "buy" — it's blocked for a short window while payment is in progress, then either confirmed (permanently deducted) or automatically released if the user never completes checkout.
This one tests whether you can design a time-bounded reservation system correctly — blocking stock without overselling it, releasing it automatically on timeout, and keeping every operation safe when a huge number of users are checking out concurrently.
Scale to consider: 10M active users, 5M products, ~1M orders/day — in-memory only, so thread-safety and explicit race handling are P0, not optional.
Objective
The primary objective is to design and implement a thread-safe, in-memory inventory service for 10M users / 5M products / ~1M orders/day that supports adding and restocking products, blocking stock for a 5-minute checkout window, and either confirming or auto-releasing that blocked stock — with explicit handling of race conditions.
Functional Requirements
Requirements are split into two tiers so you know what to prioritize under time pressure: build first, and build if time allows.
Part 1 — Core Requirements
Core functionality you must build and get working first.
In-memory only — no DB. Thread-safe for 10M active users, 5M products, ~1M orders/day; blocking, confirming, and auto-releasing can race on the same product at the same instant — handle race conditions explicitly.
Part 2 — Suggested Extensions
confirmOrder(orderId) and cancelOrder(orderId) should both be idempotent — calling either twice (e.g. due to a retried payment webhook) must not double-deduct stock or double-release it.
Example Usage: Full Walkthrough
Here's how a sample session might run end-to-end, one step at a time.
1. Register and restock a product
> addProduct("p1", "Wireless Mouse", 100)
✅ Product p1 added with stock 100.
> updateInventory("p1", 20)
✅ Stock updated. Available: 120.
2. Block stock during checkout
> blockInventory("p1", 5, "order101")
✅ 5 units blocked for order101. Available: 115. Block expires in 5 min.
> getInventory("p1")
115
3. Confirm the order before the block expires
> confirmOrder("order101")
✅ Order order101 confirmed. 5 units permanently deducted. Available: 115 (unchanged — already excluded).
Total stock: 115.
4. A block that's never confirmed auto-releases
> blockInventory("p1", 10, "order102")
✅ 10 units blocked for order102. Available: 105. Block expires in 5 min.
... 5 minutes pass with no confirmOrder call ...
⏱ Block for order102 expired. 10 units released. Available: 115.
5. Concurrent blocks can't oversell
> blockInventory("p1", 100, "order103") // from thread A
> blockInventory("p1", 50, "order104") // from thread B, same instant
✅ order103: 100 units blocked. Available: 15.
❌ order104: only 15 units available, cannot block 50.
Confirmed stock is deducted permanently, an unconfirmed block silently expires and returns its units to availability, and two concurrent block attempts on the same product never oversell — the second is correctly rejected once the first exhausts the remaining stock.