[Experience] Meesho Machine Coding Round – Inventory Management System (with solution)
Hey everyone,
Recently gave a machine coding interview at Meesho. Sharing the problem and my approach — hopefully useful for folks prepping for similar rounds at e-commerce companies.
Problem: Inventory Management Service
Design an in-memory inventory service for an e-commerce platform with the following APIs:
addProduct(productId, name, count) – Register a new product
getInventory(productId) – Get available stock
updateInventory(productId, count) – Supplier restocks a product
blockInventory(productId, count, orderId) – Block stock when user initiates payment (holds for 5 min)
confirmOrder(orderId) – Permanently deduct blocked stock on payment success; if not called within 5 min, release the block automatically
Constraints:
In-memory only, no DB
Thread-safe (10M active users, 5M products, ~1M orders/day)
Handle race conditions explicitly
My Approach
Data structures:
products dict: productId → Product object
quantity dict: productId → available count (separated from Product to avoid holding product-level locks for reads)
product_lock dict: productId → threading.Lock() — per-product lock so concurrent operations on different products don't block each other
orders dict: orderId → Order object with expiry timestamp
Key design decisions:
Per-product locking instead of a global lock — a single global lock would serialize all inventory ops across all 5M products, killing throughput. Per-product locks mean operations on Product A and Product B are fully concurrent.
Optimistic block-then-expire pattern — when blockInventory is called, stock is immediately deducted from quantity. This prevents double-selling. A background cleanup thread periodically scans for expired orders and releases stock back.
Cleanup thread — runs in a daemon thread, sleeps 1s between scans, iterates over active orders and releases expired ones under the product lock to avoid race between expiry release and concurrent confirmOrder.
Code (Python)
Code block
import time
import threading
class Product:
def __init__(self, product_id, name, count=0):
self.product_id = product_id
self.name = name
self.count = count
class Order:
def __init__(self, order_id, product_id, quantity, expiry):
self.order_id = order_id
self.product_id = product_id
self.quantity = quantity
self.expiry = expiry
class InventoryService:
def __init__(self):
self.products = {}
self.quantity = {}
self.product_lock = {}
self.orders = {}
def addProduct(self, product_id, name, inventory_count):
if product_id in self.products:
return
self.products[product_id] = Product(product_id, name, inventory_count)
self.quantity[product_id] = inventory_count
self.product_lock[product_id] = threading.Lock()
def getInventory(self, product_id):
if product_id not in self.products:
return None
return self.quantity.get(product_id)
def updateInventory(self, product_id, additional_quantity):
if product_id not in self.products:
return False
with self.product_lock[product_id]:
self.quantity[product_id] += additional_quantity
return True
def blockInventory(self, product_id, order_quantity, order_id):
if product_id not in self.products:
return False
with self.product_lock[product_id]:
if self.quantity[product_id] < order_quantity:
return False
self.quantity[product_id] -= order_quantity
expiry_time = time.time() + 300 # 5 min
self.orders[order_id] = Order(order_id, product_id, order_quantity, expiry_time)
return True
def confirmOrder(self, order_id):
if order_id not in self.orders:
return False
order = self.orders[order_id]
with self.product_lock[order.product_id]:
if order_id not in self.orders: # re-check inside lock
return False
del self.orders[order_id]
return True
def _cleanup(self):
while True:
time.sleep(1)
now = time.time()
for order_id in list(self.orders.keys()):
order = self.orders.get(order_id)
if order and now > order.expiry:
with self.product_lock[order.product_id]:
if order_id in self.orders: # double-check inside lock
self.quantity[order.product_id] += order.quantity
del self.orders[order_id]
def start_cleanup(self):
t = threading.Thread(target=self._cleanup, daemon=True)
t.start()What I'd improve with more time
orders dict itself needs a lock — concurrent blockInventory and _cleanup both mutate it; in production you'd use a threading.Lock or concurrent.futures safe structure around it
Lazy expiry — instead of a background scan, check expiry at confirmOrder time and reject stale orders; cleaner for low-order-volume scenarios
Metrics/observability — track block → confirm conversion rate, expiry rate per product
Persistence layer interface — even if in-memory for now, abstract behind a repository so swapping to Redis is a single-file change
Feel free to ask questions or suggest improvements. Happy to discuss trade-offs on the locking strategy.
Tags: #machinecodinginterview #systemdesign #python #threading #meesho
A few notes before you post: the expiry attribute in your original code has a bug — cleanup references order.expiry_time but the field is named expiry. Also the cleanup thread uses a stale snapshot of self.orders (all_order = self.orders before the loop). The version above fixes both. Worth mentioning the bugs you caught/fixed — interviewers respect that.