Skip to content

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

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

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

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:51
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

This PR addresses the demo checkout oversell/race scenario by preventing inventory from going negative under concurrent checkouts and by treating “out of stock” as an expected outcome when running the concurrent repro harness.

Changes:

  • Add a post-delay availability check in reserveStock to prevent overselling during concurrent reservations.
  • Update the concurrent checkout scenario runner to use Promise.allSettled and 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 post-delay inventory guard and aligns returned reservation metadata with the committed record state.
demo_app/src/checkout/submit-order.ts Changes concurrent scenario execution to tolerate expected OutOfStock rejections while still surfacing unexpected failures.

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

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.

runCheckoutRaceScenario is classifying expected failures by checking Error.message.startsWith("OutOfStock:"). This is brittle (message text changes/bundling can break it) and couples checkout flow to a string format. Prefer a structured signal (e.g., a dedicated OutOfStockError class, an exported type guard like isOutOfStockError(), or a stable error code property) and check that instead.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +25
if (record.available < quantity) {
throw new Error(`OutOfStock: ${sku}`);
}
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 in-function comment above the delay still says the delay is an “intentional bug” that makes the pre-check stale, but the newly-added post-delay availability check changes the behavior (the stale pre-check is now mitigated). Please update that comment to reflect the current intent so future readers don’t think the race is still present by design.

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