Rocon·Software Review

inventory · 2026-11-03 · 8 min

Preventing Dual Sales of Your Last Unit Across POS and Online

Why the last unit gets sold twice, and where to put the lock

By the Rocon editors · last checked 2026-11-03

You have to decide right now whether an in-person cashier can stall a web checkout, or whether an online buyer can block a physical register. If your store has one unit of a product left on the shelf, you cannot satisfy both customers at the exact same millisecond. You must place an authoritative lock somewhere in your stack, or accept that you will periodically cancel an order and apologize to an angry customer.

In our migrations for retail businesses with two to twenty staff members, this is the single architectural problem that causes the most friction. Platform sales reps will tell you that their systems synchronize inventory in real time. In practice, real-time inventory synchronization over public networks does not exist. There is always a latency window, and the way your software handles that window dictates whether you double-sell that final unit.

The Anatomy of a Race Condition at the Counter

The double-sale problem is not caused by slow internet or poor hardware. It is a fundamental concurrency problem. When stock reaches one unit, two independent checkout processes can read that single balance simultaneously, determine that the item is available, and proceed to payment processing before either system has notified the other of the deduction.

We have watched this play out repeatedly during holiday rush periods. An item sits on a rack near the register. A customer carries it to the counter, and the cashier scans the barcode. At that moment, the point of sale (POS) reads stock level as one. Across town, an online customer has the exact same SKU in their web cart and clicks the final payment submission button. The web platform reads the stock level as one.

Both systems initiate the capture step because both systems verified stock availability a few hundred milliseconds prior. The physical card chip processes in two to three seconds. The online payment gateway authorizes in one to two seconds. Both succeed. Both systems commit the deduction, writing the new stock level as zero or negative one. You now owe two different people the same physical box.

The Webhook Lag Window

Most small-to-midsize retail stacks connect an e-commerce platform to a physical POS via software-as-a-service (SaaS) connectors or native webhooks. The architecture relies on asynchronous event notifications: when an order occurs on platform A, platform A emits an HTTP payload telling platform B to decrement its inventory.

We tested payload delivery times across multiple standard SaaS connectors during mid-day business hours. In quiet periods, a webhook usually lands in two to five seconds. Under moderate queue pressure, we routinely observed delivery times ballooning to forty seconds, and occasionally up to five minutes.

During that delivery gap, platform B has no knowledge that the item is gone. The inventory remains displayed as available to staff and online shoppers alike. If your cashiers rely on the POS screen to know whether an item can be sold, they are operating on stale data for up to several minutes after every single web sale.

The Register Cache Illusion

To keep counter lines moving quickly, nearly every modern tablet or desktop POS caches inventory locally in memory or in an embedded database. When a cashier scans an item, the interface cannot afford to execute an un-cached round-trip API call to a distant server to verify availability; doing so would introduce half-second freezes between scans.

This caching makes the user interface fast, but it divorces the register from current truth. Even if an inventory event has reached the cloud backend of your POS platform, the individual terminal sitting on your sales counter may only poll for differential updates every five, ten, or fifteen minutes. Until that cache invalidation cycle runs, the local register believes the last unit is safely on the shelf.

The Three Places You Can Put the Lock

To prevent two transactions from claiming the same unit, one transaction must acquire a lock on the inventory record, complete its authorization, decrement the counter, and release the lock before the second transaction can read the remaining balance. You have three primary places to implement this mechanism, each with distinct operational costs.

ArchitectureRead LatencyOffline ResilienceOversell RiskOperational Cost
Central Database Row Lock100ms – 400msZero (Counter halts if internet drops)Near zeroHigh (Requires custom API or direct ERP integration)
Buffer Stock DecouplingUnder 10ms (Local)Complete (Registers continue operating)Low (Traded for artificial out-of-stock states)Low (Configured in software settings)
Asynchronous Webhook SyncUnder 10ms (Local)Complete (Registers continue operating)High during peak volumeLow (Standard off-the-shelf connectors)

Centralized Authoritative Database (Pessimistic Locking)

The only absolute prevention against double-selling is a single database that handles every stock mutation through transactional row locks. In relational databases like PostgreSQL, this is traditionally accomplished using an explicit row-level locking mechanism such as SELECT FOR UPDATE.

When the online store processes a payment, it opens a database transaction, locks the specific SKU row, decrements the balance, and commits. If the POS attempts to ring up the same SKU at the same time, its transaction is forced to wait until the web transaction commits, at which point the POS reads a balance of zero and refuses the sale.

The catch is availability. If your retail counter depends on a direct cloud transaction to ring up a purchase, an internet outage halts your physical business. Cashiers cannot scan items because the register cannot acquire the lock. For businesses with 2 to 20 staff, maintaining the infrastructure required for high-availability pessimistic locking across physical locations is rarely cost-effective or practical.

Buffer Stock Thresholds (Safety Stocking)

The most common real-world alternative is artificial decoupling through safety thresholds. Instead of synchronizing down to the final unit, you deliberately hide stock from the online platform when availability falls below an arbitrary threshold—typically one or two units.

Under this model, when inventory on a SKU drops to one, the system automatically marks it out of stock on your website, reserving that physical item exclusively for walk-in traffic. Alternatively, you reserve the last unit for web fulfillment and instruct floor staff that any single-unit items on the floor are flagged for order pickup.

This eliminates 95 percent of race conditions without requiring complex distributed locking. The obvious penalty is lost revenue: you will turn away online buyers for items that are sitting physically unsold in your back room. In our experience, stores with fast inventory turnover accept this tradeoff happily, while stores selling unique, high-ticket vintage items or one-offs find it unacceptable.

Month Two: When the Seams Start Leaking

Every inventory synchronization system looks functional during the test week when order volume is low and managers are carefully monitoring every transaction. The real failures appear around week six or seven, when standard operational chaos reasserts itself.

We have found that human edge cases routinely defeat automated locking rules. A common pattern involves customer returns. A customer returns a shirt to the physical store. The clerk processes the return, and the system correctly adds the unit back into available stock. However, the clerk places the physical shirt on a return rack behind the counter to be steamed and tagged later.

Because the system immediately pushed that single unit to the website, an online shopper buys it forty minutes later. When the fulfillment team goes to pick the item from the sales floor the following morning, they cannot find it, because it is buried under a pile of unprocessed returns behind register two. The software did not fail; the operational cadence drifted away from the software’s transactional assumptions.

A similar breakdown occurs with informal holds. Staff members frequently pull an item aside because an in-store shopper says they will return with a credit card in an hour. If the cashier does not explicitly ring that item up as an administrative layaway or manual hold, the lock is never placed. The online platform continues to sell the ghost inventory. By month two, when floor staff stop following strict manual hold procedures, ghost sales spike, and teams inevitably blame the inventory sync software rather than the missing workflow locks.

Offline Operation and the Inevitable Compromise

If you run a retail location, you will lose internet connectivity. Road construction cuts a fiber line, a router overheats, or an upstream ISP experiences a routing failure. You must know in advance how your POS will behave when it cannot reach your locking authority.

Distributed systems literature frames this through the CAP theorem: in the presence of a network partition, you must choose between consistency and availability. You can refuse to ring up the sale until the connection returns (choosing consistency), or you can let the cashier complete the transaction using local cached data (choosing availability).

In every small retail deployment we have ever worked on, the business owner invariably chooses availability. No store manager is willing to tell five customers standing in line with merchandise that they cannot pay because an offsite server is unreachable. The register falls back to optimistic local operations. It assumes the cached stock is correct, rings the sales, and queues the mutations locally.

When connectivity returns, the register flushes its queue to the cloud. If an online customer bought that same remaining unit during the thirty-minute network drop, the collision occurs retroactively. No software configuration can avoid this. You have to decide whether your operational priority is never overselling, or never turning away a human being holding a physical item at your counter.

What We Would Actually Choose

If we were setting up a retail operation with 2 to 20 staff today, we would not attempt to build a unified real-time distributed lock across web and in-person registers. Instead, we would choose a modern SaaS POS with native e-commerce integration, configure a hard safety buffer of one unit on all shared SKUs, and enforce an ironclad rule on the floor: the physical register always wins, the online buyer is refunded if a rare collision slips through the buffer, and staff never hold an item behind the counter without scanning it into a dedicated administrative quarantine location.