Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses the checkout-race-condition incident in the demo checkout-api flow by preventing overselling during concurrent reservations and by making the concurrent repro scenario tolerate expected “out of stock” outcomes.
Changes:
- Add a commit-time inventory availability check in
reserveStockto prevent concurrent oversell. - Return reservation metadata based on the committed inventory record version (not the pre-check snapshot).
- Update the concurrent checkout scenario to use
Promise.allSettledand only fail the scenario for non-OutOfStock errors.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| demo_app/src/inventory/reserve-stock.ts | Adds a post-delay guard against stale snapshot checks and returns committed snapshot version/token. |
| demo_app/src/checkout/submit-order.ts | Treats OutOfStock as an expected concurrent outcome while still surfacing unexpected failures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| await delay(25); | ||
|
|
||
| const record = getInventoryRecord(sku); | ||
|
|
||
| if (record.available < quantity) { |
There was a problem hiding this comment.
The concurrent-staleness comment immediately above this delay reads like the race is still an intentional bug, but the new post-delay availability guard changes that story. Please update the comment to describe the current behavior (snapshot pre-check can be stale, but the commit-time record check prevents overselling) so future readers don't assume the function is still intentionally incorrect.
| const hardFailure = settled.find( | ||
| (result) => | ||
| result.status === "rejected" && | ||
| !(result.reason instanceof Error && result.reason.message.startsWith("OutOfStock:")) | ||
| ); |
There was a problem hiding this comment.
Using error.message.startsWith("OutOfStock:") to classify expected rejections is brittle (it couples control flow to a string that can change and doesn’t work for non-Error rejections). Prefer a structured signal (e.g., a dedicated OutOfStockError class, error.name, or an error code field) so this filtering remains stable as messages evolve.
Summary
Resolve
checkout-race-conditionforcheckout-apiwith a validated ReplayX patch candidate.Changed Files
Validation
Rollback
Revert the live inventory guard and concurrent checkout settlement handling.