Repository navigation
fix(purchase): refuse retry and re-drive of AWS EC2 and Redshift purchases - #778
Conversation
…r an unknown outcome EC2 and Redshift purchase APIs take no client token, so the provider now sends them once and reports a lost response as "purchase outcome unknown": the commitment may exist. The platform still treated every AWS purchase as safe to re-drive, so the stranded-approval sweep, the reaper's "safe to retry" note, the executor backstop for retry successors and the Retry endpoint could all buy a second commitment. recRedriveRefusalReason now refuses AWS recs whose service dispatches to the EC2 or Redshift client (ec2, compute, redshift, data-warehouse, matched through mapServiceSlug so the guard and the executor cannot drift). A first purchase still executes; only re-drive and retry are refused. The refusal text tells the operator to check EC2 Reserved Instances or Redshift Reserved Nodes in the target account and region and to start a new purchase if the commitment is missing. The stranded-row message no longer points at the refused Retry. Bumps providers/aws to bcc0dfc, which sends these purchases once. Refs LeanerCloud/cloud-commitments-go#296 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…-unknown-no-redrive
|
Subject: platform PR 778 (MON-02 platform half) @ 1d933ad - APPROVE conditional on green CI; one heads-up for the PR body Reviewed 3a15d5a in full, then the merge head 1d933ad. Delta check: the PR's own changes are byte-identical (added/removed lines of 27c1a30..3a15d5a equal those of fe13430..1d933ad, md5 equal); the merge only brings main (incl. #772 gcp, #766, #773-adjacent). go.mod vs main: providers/aws 9962786e -> bcc0dfc49227 only (gcp 2c18f303 comes from main); go.sum hash for bcc0dfc matches
|
At the pinned providers/aws the EC2 client rejects an empty or unknown Tenancy or Scope before sending the request instead of substituting a default. Two comments still described the old defaulting behaviour. Comment-only change. Refs LeanerCloud/cloud-commitments-go#296 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The AWS EC2 client rejects an empty Platform and an empty or unknown Tenancy or Scope before sending the request. Drop the Linux/UNIX default example, which applies to exchange only, and stop naming a buildOfferingFilters function that does not exist. Comment-only change. Refs LeanerCloud/cloud-commitments-go#296 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Gate check (gate-1) at head c5e1f00: not merged, head is behind main.
|
|
Gate verdict (gate-1): PASS at bc5efe3, merging.
|
Summary
Platform half of go#296. The Retry endpoint, the stranded-approval sweep, the reaper's retry advice and the executor backstop for retry successors now refuse to re-drive any AWS EC2 or Redshift purchase, so a lost response can no longer lead to a second commitment. Go half: merged as bcc0dfc (go#297), which sends these purchases once and reports a lost response as
purchase outcome unknown.Closes LeanerCloud/cloud-commitments-go#296
The refusal is by service, not by outcome
After ANY failure of an EC2 or Redshift execution, retry and re-drive are refused. That includes definite rejections: a 4xx, throttling, credentials errors, "no offerings found", and the new pin's rejection of an empty Tenancy or Scope. The platform cannot tell a definite failure from an unknown outcome because the go sentinel
purchasecfg.ErrOutcomeUnknownis in an internal package and persisted errors are flattened to strings, and reaped or stranded rows carry no error at all. The operator checks the account and starts a new purchase. Exporting the sentinel so definite failures can be retried is go#301.Problem
The EC2 and Redshift purchase APIs take no client token or caller ID.
recRedriveRefusalReason(internal/purchase/manager.go) still said every AWS service honours a token, so four paths could buy a second commitment:RecoverStrandedApprovals) re-drove the row in place;?force=truedoes not override a refusal);armedRedriveRefusalbackstop).Change
recRedriveRefusalReasonrefuses AWS (and legacy empty provider) recs whose service dispatches to the EC2 or Redshift client:ec2,compute,redshift,data-warehouse. Matching goes throughmapServiceSlug, the table the executor dispatches on, so guard and dispatch cannot drift. One predicate feeds all four paths.go.mod:providers/awsbumped to bcc0dfc (only that module). Two comments that described the old EC2 Tenancy/Scope defaulting are corrected (comment-only commit e832349).Pin move heads-up (found in review)
The
providers/awspin moves from 9962786e to bcc0dfc, and that is more than the MON-02 commit: it pulls 17 providers/aws commits (42 files). Notable behaviour for platform consumers:ExistingCommitmentadopted flag on EC2/RDS/ElastiCache/MemoryDB/OpenSearch re-drives (fix(api): openapi.yaml omits ~30 routed paths and mis-describes documented operations #262); bounded idempotency scans (fix(frontend): savings-analytics summary keys read by the client never exist on the wire #276); Go 1.26.9 bump.Platform consumers of the adopted flag are not in this PR.
Not in this PR
ErrOutcomeUnknownso definite failures can be retried: go#301.ApproveAndExecuteEC2 retry-refusal test (the funnel is shared, covered today by structure and the Azure armed tests): platform#780.ec2:CreateTagsin member-account roles): fix(iac): grant ec2:CreateTags to member-account purchase roles so the idempotency tag is written #702.purchase_historydedupe on re-drive: fix(purchase): skip duplicate purchase_history insert on re-drive and add a unique index #704.Tests
internal/purchase/aws_no_token_redrive_test.go(new): guard reach equals dispatch reach for aws and "" over spellings and case variants; closed refusal set with negative controls; retry successor of ec2/compute/redshift/data-warehouse buys nothing and is persisted failed with the reason, first purchase buys once; stranded EC2 row makes zero provider calls.reaper_test.go: reaped EC2 row has no "safe to retry"; the RDS test is the positive control.handler_purchases_retry_redrive_test.go: Retry of failed aws/ec2, compute, redshift, data-warehouse and legacy "" rows returns 409redrive_unsafewith and without?force=trueand fires no purchase; an RDS retry still buys once.Verification (local, macOS)
go build ./...,go vetandgo testofinternal/purchaseandinternal/apipass. Not run: real AWS (no live cloud calls or purchases).🤖 Generated with Claude Code