Skip to content

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

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

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

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

Resolves the checkout-race-condition in checkout-api by preventing overselling during concurrent inventory reservations and adjusting concurrent checkout handling to tolerate expected out-of-stock failures.

Changes:

  • Add a commit-time (post-delay) inventory availability guard in reserveStock to prevent negative inventory under concurrency.
  • Make concurrent checkout use Promise.allSettled and treat OutOfStock rejections as expected while still surfacing unexpected failures.

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 aligns returned reservation metadata with the committed record state.
demo_app/src/checkout/submit-order.ts Switches concurrent execution to allSettled, ignoring expected OutOfStock failures while propagating other errors.

💡 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.

Classifying an expected failure by checking error.message.startsWith("OutOfStock:") is brittle (message text changes will alter control flow). Prefer a dedicated OutOfStockError (or an error.code field) thrown from reserveStock, and filter using instanceof/code instead of string parsing.

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.

Now that a post-delay availability check is added (and the concurrent negative-inventory path should be prevented), the nearby comment describing this delay as an "Intentional bug" is misleading. Update the comment to reflect the current behavior (e.g., that the delay simulates latency but the commit-time check prevents oversell).

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