[Experience] Meesho Machine Coding Round SDE3– Inventory Management System (with solution)
Summary
I completed a machine‑coding round for an SDE3 position at Meesho, where I was asked to design an in‑memory inventory management service and I presented a thread‑safe Python implementation.
Full Experience
[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 productgetInventory(productId)– Get available stockupdateInventory(productId, count)– Supplier restocks a productblockInventory(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 objectquantity 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 otherorders 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
blockInventoryis 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 1 s 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)
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
ordersdict itself needs a lock — concurrentblockInventoryand_cleanupboth mutate it; in production you'd use athreading.Lockor a concurrent‑safe structure around it- Lazy expiry — instead of a background scan, check expiry at
confirmOrdertime 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
Interview Questions (1)
Inventory Management Service Design
Design an in‑memory inventory service for an e‑commerce platform with the following APIs:
addProduct(productId, name, count)– Register a new productgetInventory(productId)– Get available stockupdateInventory(productId, count)– Supplier restocks a productblockInventory(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