Skip to content

fix(purchase): run execution and terminal save outside the 30s HTTP request context #706

Closed

Description

@cristim

Summary

Synchronous purchase execution runs on the 30s HTTP request context, and the terminal status save uses the same context. If the request is cancelled mid-purchase, the cloud purchase may have succeeded but the final state is never written ("AUDIT LOSS"). There is no stuck-purchase reaper on GCP or Azure.

Where

At commit b50ca38:

  • internal/server/http.go:234
  • internal/purchase/manager.go:220-249

Failure scenario

A purchase takes longer than 30s, or the client disconnects. The context is cancelled after the provider call returned but before the terminal save, so the execution stays non-terminal while the commitment exists. On GCP and Azure nothing reaps it, and a retry can buy again. Found by source reading; not reproduced live.

Suggested fix

Run the purchase and its terminal save under context.WithoutCancel with its own timeout, or return 202 and execute asynchronously. Wait for in-flight executions on SIGTERM.

Severity

High: a completed purchase can be left unrecorded, which loses the audit trail and invites a double buy.

Related: #105, #258, #664 (related, but not the synchronous purchase path).

Reviewer ID: MON-10 (ops H3)
Found by the 2026-10-08 review fleet.

Activity

  1. cristim commented on Oct 14, 2026

    @cristim
    MemberAuthor

    Merged normally in PR #789 at 54fdacf, from independently reviewed head 9eb15eb. All 25 PR checks passed. Local macOS verification exercised the authenticated production handler, persisted claim, real native PostgreSQL, manager/store/migrations and completed/failed cancellation outcomes; a repeat request made no second provider call. Provider/authentication inputs were simulated, and no live cloud purchase or production deployment verification is claimed. Removing cancellation detachment and moving the save context before execution each failed the regression proofs. Exact reviewer and verification evidence is recorded on the PR. Existing RI-exchange and scheduled-task follow-ups remain tracked in #790 and #784.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions