[Experience] Meesho Machine Coding Round SDE3– Inventory Management System (with solution)
423
Apr 10, 2026
Apr 10, 2026

[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.

Comments (1)