Repository navigation
fix(api): keep marketplace listing tracked when rollback cancel fails - #506
Merged
Merged
Conversation
When a created listing could not be persisted and the compensating CancelReservedInstancesListing also failed, reserveAndCreateListing released the claim (restoring the pre-listing fields) and reported the listing as rolled back, leaving a live AWS listing the platform no longer tracked and a row from which a duplicate listing could be made. On that branch, record the known listing ID and state instead of releasing the claim, so marketplace-cancel can reach it, and return a 502 naming the listing and the AWS cancel error. If that write also fails, the row keeps its pending claim, which blocks a second listing, and the message says an operator must reconcile it. Closes #335
Contributor
|
Warning Review limit reached
This review includes 3 billable files and costs up to $0.75.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 1 minute for your next included review. View limit detailsLimit details: You’ve used all 2 included reviews currently available. Your 50 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (3)
Comment |
The compensating cancel and the second DB write reused the request context. A request deadline or client disconnect is the likeliest cause of the first write failing, so both would fail too, leaving the row pending with no listing ID. Run them under a detached 10s context. When the recorded AWS state is not active, say the listing needs reconciliation instead of advising another cancel (a pending listing cannot be canceled through the API). An empty AWS state is recorded as pending, since the claim SQL treats an empty state as free.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
reserveAndCreateListing(internal/api/handler_marketplace.go): when AWS created a listing, the DB write of that listing failed, and the compensatingCancelMarketplaceListingalso failed, the handler still released the claim (restoring the pre-listing fields) and returned "listing has been rolled back". The AWS listing stayed live, the row no longer referenced it, and the released claim allowed another listing to be created.Fix
Only that branch changes (new helper
keepUncanceledListing):active) instead, using the existingUpdatePurchaseHistoryListingand listing-state constants. This is the same number of DB writes as before (it replaces the release write). With the listing recorded,marketplace-cancelcan cancel it, andClaimMarketplaceListingSlotblocks a duplicate listing.pendingclaim. That claim blocks a duplicate listing, and the message tells the operator to reconcile the listing.ClientErrorthat names the listing ID and the AWS cancel error. This follows the existingmapAWSMarketplaceError502 pattern. The DB error text is logged and not returned. Previously this path returned a generic 500 that said nothing about rollback.Unchanged: the path where compensation succeeds (cancel succeeds, claim released, "rolled back"), and the path where create fails.
Verification
Toolchain:
GOTOOLCHAIN=go1.26.6 GOWORK=off GOFLAGS='-p=2 -count=1' AWS_EC2_METADATA_DISABLED=trueTestMarketplaceList_DBFailureAndCancelFailureKeepsListing(mock store) covers two cases: the listing gets recorded, and the DB stays down. It asserts 502, no "rolled back", the listing ID and AWS error in the message, and no release write ("", "").TestMarketplaceListCancelFailureKeepsListingRecordeduses real Postgres via testcontainers. The store wrapper fails only the first listing write, and the EC2 client is a stub. The test asserts the row holdsril-default/active, a second list attempt is refused without calling AWS create again, and a later successful cancel moves the row tocancelled."", "") also fails both. The integration test reportsexpected: "ril-default" actual: ""and "An error is expected but got nil" (a duplicate listing was created). The mutation was then reverted.go build ./...,go vet ./...,go vet -tags integration ./internal/api/ ./internal/config/all clean.go test ./internal/api/ ./internal/config/ ./internal/server/: 3640 passed.go test -tags integration ./internal/api/ -run Marketplace: 106 passed.golangci-lint run ./internal/api/...: no issues.All of this evidence uses mocks or fixtures (stub EC2, injected DB failure). No real AWS listing was created.
Deliberately left
activestate on create (e.g.pending), the recorded row can't be canceled throughmarketplace-canceluntil the status poller (RI Marketplace: status poller (active->closed + proceeds/fee) + seller-account precondition UI (closes #292 remainder) #27) exists. That poller is out of scope here.Closes #335