Skip to content

fix(checkout-api): resolve checkout-race-condition#17

Open
Spkap wants to merge 1 commit intomainfrom
replayx/incident-checkout-race-001-mo654kss
Open

fix(checkout-api): resolve checkout-race-condition#17
Spkap wants to merge 1 commit intomainfrom
replayx/incident-checkout-race-001-mo654kss

Conversation

@Spkap
Copy link
Copy Markdown
Collaborator

@Spkap Spkap commented Apr 19, 2026

Summary

Resolve checkout-race-condition for checkout-api with a validated ReplayX patch candidate.

Changed Files

  • demo_app/src/inventory/reserve-stock.ts
  • demo_app/src/checkout/submit-order.ts

Validation

  • Concurrent checkout repro: exit 0
  • Sequential checkout sanity: exit 0

Rollback

Revert the live inventory guard and concurrent checkout settlement handling.

Copilot AI review requested due to automatic review settings April 19, 2026 19:10
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Resolves the checkout-race-condition repro path in the demo checkout API by preventing over-reservation under concurrent requests and by handling expected “out of stock” failures without failing the whole concurrent scenario.

Changes:

  • Add a live inventory availability re-check right before committing the reservation to avoid stale pre-checks under concurrency.
  • Return reservation metadata (token + snapshot version) from the committed inventory record rather than the stale snapshot.
  • Switch concurrent checkout scenario execution to Promise.allSettled, surfacing only “hard” failures while tolerating expected OutOfStock rejections.

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 post-delay availability guard and returns committed snapshot/version info.
demo_app/src/checkout/submit-order.ts Uses allSettled to tolerate expected OutOfStock failures during concurrent scenario runs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 19 to +23
await delay(25);

const record = getInventoryRecord(sku);

if (record.available < quantity) {
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The concurrency window comment above the delay now reads like a still-present bug, but the new post-delay record.available guard changes the behavior. Update the comment to reflect that the delay is only simulating a race window and that availability is re-validated against the live record before commit (or remove the delay if it’s no longer intended).

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +23
const hardFailure = settled.find(
(result) =>
result.status === "rejected" &&
!(result.reason instanceof Error && result.reason.message.startsWith("OutOfStock:"))
);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This treats expected failures by parsing error.message (prefix match) which is brittle and easy to break during refactors/localization. Consider introducing a typed OutOfStockError (or an error.code field) and switching this logic to a helper like isOutOfStockError(reason: unknown) so control flow isn’t coupled to the exact message text.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants