Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses the checkout-race-condition incident in the demo app by preventing overselling during concurrent checkouts and ensuring the concurrent repro path no longer fails due to expected “out of stock” rejections.
Changes:
- Add a post-delay availability guard in
reserveStockto prevent committing negative inventory under concurrency. - Generate reservation metadata (token + snapshotVersion) from the committed inventory record state.
- Update the concurrent checkout repro to tolerate expected
OutOfStockfailures viaPromise.allSettled.
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 availability check and returns reservation metadata based on the committed record state. |
| demo_app/src/checkout/submit-order.ts | Uses Promise.allSettled and filters expected out-of-stock rejections to keep the concurrent repro from failing. |
💡 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 inline comment describing the post-snapshot delay as an “Intentional bug” is now misleading because the new post-delay record.available < quantity guard prevents the stale pre-check from causing an oversell. Please update/remove the comment so future readers don’t think the race is still intentionally present (or clarify that the delay is retained only to simulate concurrency while remaining safe).
| const hardFailure = settled.find( | ||
| (result) => | ||
| result.status === "rejected" && | ||
| !(result.reason instanceof Error && result.reason.message.startsWith("OutOfStock:")) | ||
| ); |
There was a problem hiding this comment.
runCheckoutRaceScenario classifies “expected” failures by string-matching Error.message.startsWith("OutOfStock:"). This is brittle (message format changes will flip behavior) and couples control flow to human-readable text. Consider using a dedicated error type or a stable discriminator (e.g., error.name / code property) from reserveStock, and check that instead.
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.