How Location Groups prevent overselling across stores
When you share inventory between stores, overselling becomes your biggest risk. Here's how SyncTec's Location Groups handle race conditions and ensure you never sell the same item twice.
The #1 fear merchants have about shared inventory: overselling.
You have 1 unit left. Two customers on different stores try to buy it at the same time. Who gets it?
This post explains how Location Groups solve this problem with distributed locking.
The Problem: Race Conditions
Here's a scenario without protection:
**2:00:00.000pm:** Customer A on Store 1 adds Product X to cart. Inventory: 1 unit.
**2:00:00.100pm:** Customer B on Store 2 adds Product X to cart. Inventory: still shows 1 unit.
**2:00:01.000pm:** Customer A clicks 'Buy'. Shopify processes order. Inventory: 0 units.
**2:00:01.050pm:** Customer B clicks 'Buy'. Shopify processes order. Inventory: -1 units.
You just oversold. One customer will get an apology email and a refund. One customer will leave a bad review.
How Traditional Sync Fails
Without Location Groups, the sync might work like this:
1. Sale happens on Store 1
2. Store 1 sends webhook to SyncTec
3. SyncTec updates Store 2
This takes 200-500ms. During that time, Store 2 still shows the old inventory. Customer B can buy it.
The Solution: Distributed Locking
Location Groups use distributed locks to prevent this:
**Step 1: Reserve inventory**
When Customer A adds to cart, Shopify reserves inventory on Store 1. Other customers on Store 1 can't buy it.
**Step 2: Acquire lock**
Store 1 sends webhook to SyncTec. SyncTec acquires a distributed lock for Product X.
While this lock is held, no other store can modify inventory for Product X.
**Step 3: Update all stores**
SyncTec updates inventory on Store 2, Store 3, etc. All updates happen atomically.
**Step 4: Release lock**
Lock is released. Other stores can now process sales for Product X.
**Result:** By the time Customer B on Store 2 tries to check out, inventory is already 0. Checkout fails. No overselling.
How Fast Is This?
Lock acquisition: ~10ms
Inventory update across all stores: ~150ms
Total: ~160ms
Fast enough that the customer never notices.
What About Network Failures?
What if SyncTec crashes after acquiring the lock but before releasing it?
Locks have automatic expiration (TTL = 30 seconds). If SyncTec crashes, the lock expires and other stores can proceed.
What About API Rate Limits?
Shopify limits API calls to 2 per second per store.
If you're syncing to 10 stores, that's up to 5 seconds to update everyone.
Our solution: batch updates. We queue updates and send them in parallel to all stores. Average time: still under 200ms.
Edge Case: Simultaneous Sales on Multiple Stores
What if two customers on different stores buy the last 2 units at exactly the same time?
1. Customer A on Store 1 reserves 1 unit
2. Customer B on Store 2 tries to reserve 1 unit
3. Store 2 checks with SyncTec: 'How many units available?'
4. SyncTec sees Store 1 already reserved 1 unit. Available: 1 unit.
5. Store 2 reserves the last unit
Both sales go through. No overselling.
Testing This
We tested Location Groups with chaos engineering:
- Simulated 100 simultaneous purchases across 10 stores
- Randomly injected failures (network timeouts, API errors)
- Verified zero oversells in 10,000 test runs
The Result
Since launching Location Groups, we've processed 4 million inventory syncs.
Overselling incidents: 0.
It works.