Skip to content

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

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

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

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:52
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 demo app’s checkout-race-condition by adding a post-delay inventory availability guard and adjusting concurrent checkout handling so an expected OutOfStock outcome doesn’t fail the entire scenario run.

Changes:

  • Add a post-delay record.available check in reserveStock to prevent inventory from going negative under concurrent reservations.
  • Update reservation metadata to reflect the committed snapshotVersion.
  • Switch concurrent checkout flow to Promise.allSettled, treating OutOfStock as a non-fatal outcome 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 guard and returns committed version/token to prevent negative inventory under concurrency.
demo_app/src/checkout/submit-order.ts Uses Promise.allSettled to tolerate expected OutOfStock in concurrent mode while rethrowing other failures.

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

Comment on lines 18 to +22
// Intentional bug: this delay makes the pre-check stale under concurrent checkout attempts.
await delay(25);

const record = getInventoryRecord(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 comment about an "Intentional bug" (stale pre-check under concurrent checkout) is now outdated because a post-delay guard (record.available < quantity) was added. Please update or remove the comment so it reflects the current behavior/fix; otherwise it will mislead future readers when diagnosing race conditions here.

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.

runCheckoutRaceScenario is treating OutOfStock as a "soft" failure by inspecting Error.message.startsWith("OutOfStock:"). This is brittle (message text is not a stable contract) and duplicates the sentinel string across modules. Prefer a typed error (e.g., class OutOfStockError) or a stable discriminator (error code/name) exported from the inventory module and checked here.

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