Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses the seeded checkout-race-condition in the demo checkout-api flow by preventing inventory from being driven negative under concurrent checkout attempts and by making the concurrent repro runner tolerant of expected OutOfStock outcomes.
Changes:
- Add a post-delay “live inventory” availability guard in
reserveStockto prevent overselling after a stale pre-check. - Return reservation tokens/snapshot versions based on the committed record version rather than the pre-check snapshot.
- Update the concurrent checkout scenario to use
Promise.allSettledand only fail on 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 live inventory check after the async delay and aligns returned reservation metadata to the committed record state. |
| demo_app/src/checkout/submit-order.ts | Treats OutOfStock as an expected concurrent outcome via allSettled, while still surfacing unexpected failures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Intentional bug: this delay makes the pre-check stale under concurrent checkout attempts. | ||
| await delay(25); | ||
|
|
||
| const record = getInventoryRecord(sku); | ||
|
|
||
| if (record.available < quantity) { | ||
| throw new Error(`OutOfStock: ${sku}`); |
There was a problem hiding this comment.
The inline comment says the delay is an “Intentional bug” that makes the pre-check stale, but the new post-delay record.available guard now prevents the stale-check oversell. Please update/remove this comment so it reflects the current behavior (e.g., that the delay simulates concurrency and the second check is the actual safety guard).
| const hardFailure = settled.find( | ||
| (result) => | ||
| result.status === "rejected" && | ||
| !(result.reason instanceof Error && result.reason.message.startsWith("OutOfStock:")) | ||
| ); |
There was a problem hiding this comment.
This treats OutOfStock as a non-fatal error by matching on error.message.startsWith("OutOfStock:"), which is brittle (any message change or non-Error throw will change behavior). Prefer a typed signal (e.g., an exported OutOfStockError class, error.name === "OutOfStockError", or a small isOutOfStockError() helper co-located with reserveStock) so the concurrent settlement logic isn’t coupled to a string prefix.
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.