Description
product.model.js presumably tracks stock/quantity, and checkout.controller.js + cart.controller.js decrement it on order placement. Under concurrent checkout requests for the same product (e.g. last item in stock, two users checking out simultaneously), a classic read-then-write race condition can allow both orders to succeed, oversell the product, and leave stock negative — this is a textbook hard concurrency bug in e-commerce systems.
Tasks
- Reproduce the race with a concurrent-request test (e.g. two simultaneous checkout calls against a product with quantity=1)
- Fix using atomic MongoDB operations (
findOneAndUpdate with a quantity: { $gte: requestedQty } filter and $inc: { quantity: -requestedQty }) instead of read-then-write
- Ensure the checkout flow correctly rolls back / rejects the order if the atomic decrement fails (out of stock at the moment of commit)
- Add integration test in
BACKEND/tests/checkout.test.js that fires concurrent requests and asserts stock never goes negative and only one order succeeds when stock=1
Acceptance Criteria
- Stock quantity is never negative after concurrent checkout attempts (verified by a load-style test)
- Failed checkout due to race loses gracefully with a proper user-facing "out of stock" error, not a 500
Description
product.model.jspresumably tracks stock/quantity, andcheckout.controller.js+cart.controller.jsdecrement it on order placement. Under concurrent checkout requests for the same product (e.g. last item in stock, two users checking out simultaneously), a classic read-then-write race condition can allow both orders to succeed, oversell the product, and leave stock negative — this is a textbook hard concurrency bug in e-commerce systems.Tasks
findOneAndUpdatewith aquantity: { $gte: requestedQty }filter and$inc: { quantity: -requestedQty }) instead of read-then-writeBACKEND/tests/checkout.test.jsthat fires concurrent requests and asserts stock never goes negative and only one order succeeds when stock=1Acceptance Criteria