I used this strategy on the past:
If stock is "plenty", reduce it on checkout
Mind "plenty" is relative to sell rate, if you are on a special sales day, such as a Black Friday campaign, "plenty" could mean thousands of units, and below a thousand unit is already "few" depending on the sales rate and kind of product.
If you are selling a more exclusive or niche good, maybe "plenty" is more than 10 items in stock, or even fewer.
If stock is "few", reduce it when adding to cart and lock to a per-specified amount of time
Make that time countdown explicit to the user. You can skip reducing the actual stock, and keep a "locked" column, and then the "available" stock is "real" stock minus locked items. This will work if you keep track of expired items.
If a user have an expired item, you check availability and re-add to their cart if the cart is "active" (created not long ago or changed not long ago).
For customers wanting a "locked" item, you could consider showing some message like "in stock, but locked for XX minutes awaiting other customers", where XX would be the smallest lock minutes.
By being clear with the customer, they could add to their cart and wait in line for an item to be unlocked. This will require your platform to have a flag on the cart item so you know this item is not actually in the cart, but awaiting for one to be available.
Your scheduled job to check for expired items would:
- traverse all expired items
- for each expired item check if a customer is "waiting in line"
- if so remove from the original cart and add to the one awaiting
- If no customers are waiting for that item, check if the current cart is active (created/changed recently) and renew its expiration time
- If none of the cases above apply, just remove it from the user's cart, or mark as expired
This strategy is similar to how airplane companies and concert/event ticketing platform works.
Notes
Mind this is not the "silver bullet" for this problem. I am just sharing what I saw in practice in a project, and at the time I wasn't the one planning the features for this project.
So again I am not claiming this is the best solution.
This is a problem of a race condition (many workers wanting exclusive access to the same resource). There is no shortage of strategies on how to solve this kind of problems. Ones might not seem a good fit to your problem.
But basically the general solution varies around two aspects:
- How to manage the lock for a shared resource and
- How to manage the other workers (on your domain the customers) awaiting to access that resource
Hope this helps you shed a light on the possibilities =)