Omnichannel Inventory Sync: The Engineering Behind Real-Time Stock
We've seen "real-time inventory" mean a lot of different things depending on who you ask. To the warehouse team it means the WMS scan is reflected immediately. To the web team it means the product page shows the right number. To the marketplace integration it means the feed updates before you oversell. Getting all three to be true at the same time, across a POS system, an ERP, and two storefronts, is not a synchronization problem — it's a consistency problem, and those are harder.
Event-driven inventory architecture. Stock mutations from warehouse, POS, and ERP publish events to a central bus. Consumers (storefront, mobile, marketplace) subscribe and maintain their own read models.
Why polling breaks
The first instinct is to have each channel periodically query a central inventory database. At low volume, this is fine. As you add channels and traffic, two problems compound: read load on the inventory DB grows with every new consumer and every decrease in polling interval; and the lag between a real stock change and its appearance in each channel is at minimum the polling interval, which is rarely short enough to matter.
Run a flash sale with 10,000 concurrent users hitting the product page every few seconds and you'll find the inventory database ceiling fast. Oversells — order confirmations going out for stock that doesn't exist — are what happens when the database can't keep up and you don't have a reservation layer in front of it.
Event-driven inventory architecture
The pattern that holds up: treat every inventory mutation as an event. A warehouse scan, a POS sale, a web order confirmation — each one publishes an event to a message bus (Kafka and RabbitMQ are the common choices here). Each consuming system subscribes and maintains its own read model of current stock.
Producers don't need to know how many consumers exist. Consumers receive updates rather than polling for them. Every stock change is in the event stream in order, which gives you a usable audit log for debugging discrepancies. The web store's read model might be 1–2 seconds behind a warehouse scan, which is almost always fine. The important thing is that the write path — the actual stock decrement — is authoritative and not duplicated across systems.
The reservation pattern
The hardest edge case: what counts as "available" between "added to cart" and "order confirmed"? Without a reservation layer, two customers can add the last unit to their carts at the same time, both reach payment, and one of them gets an order confirmation for inventory that doesn't exist. This is a race condition and it happens in production.
The standard fix is soft reservations. Adding to cart creates a temporary hold with a TTL — 15 to 30 minutes is common, though this varies a lot by product type and checkout flow length. The item is counted against available stock immediately, but total stock isn't decremented yet. Successful payment converts the reservation to a permanent decrement. Cart abandonment or TTL expiry releases it back. The TTL duration involves some judgment: too short and you frustrate customers mid-checkout; too long and popular items sit "unavailable" in abandoned carts.
Eventual consistency and where it matters
Distributed inventory systems are eventually consistent — there will be moments where the web store and the warehouse are showing different numbers. That's usually fine. A 2-second lag between a warehouse scan and a storefront update doesn't cause problems for most SKUs most of the time.
Where it's not fine: the last unit. If you're down to one item, a 2-second lag is enough for two customers to both see it as available. This is where you need hard consistency, not eventual consistency. The pattern we use: treat "in stock" as a soft signal everywhere in the funnel except the final payment step. Product page, cart, checkout summary — all can read from the eventually-consistent model. The authoritative decrement happens under a database-level lock at payment confirmation. If that lock fails, you show an "item no longer available" error and the customer stays whole. It's a much better outcome than a post-purchase cancellation email.
When systems disagree
In any multi-system inventory setup you need one authoritative source of record, and it's almost always the ERP. When the web store and the warehouse show different numbers, the ERP wins. What matters is how quickly you find out they disagree.
Run a reconciliation job on a short interval — every 5 to 15 minutes, not nightly. Compare each channel's read model against ERP state and publish correction events for any discrepancy. The goal isn't perfection; small gaps happen constantly and are fine. What you're catching is the divergence that builds over hours: a missed event, a failed consumer, a deploy that briefly dropped messages. Those are the discrepancies that become oversell incidents. Find them at 10 minutes and you fix them with a correction event. Find them at 10 hours and you're issuing refunds and writing an incident report.
Следующий шаг
Работаете над сложной commerce-системой?
Мы помогаем инженерным командам проектировать, строить и масштабировать высоконагруженные платформы — с чётким процессом и предсказуемыми сроками.
Поговорим