Repository navigation
feat(purchase): refuse a Redshift dispatch while another lineage of the tuple is open - #1807
Conversation
Part of #702 (Redshift re-drive idempotency, PR2 commit 1). FindOpenRedshiftLineageConflictsTx lists other executions that could still buy the same Redshift tuple (region, node type, term, payment, count, account) as a dispatch about to happen, inside the caller's transaction: - A running row conflicts once stamped, at any stamp age, including a same-family row with another execution ID (a parallel retry). - Approved, scheduled, pending, notified and paused rows of another family conflict while their stamp is within the horizon, judged on the DB clock. - The account side is the row's account or else the rec's, and a missing account on either side matches any, so fan-out roots are matched per rec account and unknown accounts fail closed. - A non-array recommendations value is treated as no recs. Failed rows are not considered yet; they join with the guard lift. Not called yet; the dispatch gate comes in a later commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #702 (Redshift re-drive idempotency, PR2 commit 2). - Region, node type, term, payment and count must all match; a count that differs either way is not a conflict. - Only selected aws (or legacy empty provider) redshift and data-warehouse recs count. - The account rule (row account else rec account, against tuple account else the candidate's, a missing account on either side matching any) is checked over every combination. - A rec cloud_account_id that is not a uuid is now treated as a missing account, which matches any, instead of failing the whole query. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #702 (Redshift re-drive idempotency, PR2). Before a Redshift buy, one transaction now: 1. takes a pg_advisory_xact_lock per purchase tuple (region, node type, term, payment, count; sorted), after forcing READ COMMITTED so the check below sees a lineage that committed while this one waited; 2. stamps first_dispatch_at; 3. looks for another open lineage that could buy the same tuple. A conflict rolls the stamp back and refuses the dispatch before any purchase call. A stamp outside the 24h re-drive horizon, or a missing stamp on a later attempt, is a plain error: an earlier attempt may have bought, so it must not read as "nothing was submitted". Fan-out per-account rows still inherit the root's stamp and never take the gate themselves. Redshift re-drive stays refused; the guard lift comes later. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #702 (Redshift re-drive idempotency, PR2). The conflict refusal named the other execution. Because a NULL account matches any account, that execution can belong to another account, so the stored and displayed error could leak it. The conflict, horizon and missing-stamp refusals are now fixed texts. The execution ids go to the server log only, and the errors allowlist shows the texts verbatim. Integration tests on a real database cover: - a conflicting open lineage rolls the stamp back and buys nothing; - two lineages of one tuple racing the gate buy once; - a root row and its per-account successor in one family buy once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 33 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
APPROVED b2ccdef by claude-ui-fix-2 Cold review of #702 PR2 (+983/-15, no migration), judged as fail-closed: the gate may refuse more than it needs to, but it must never let a duplicate through. Where the gate sits
That's after the CAS claim to
The gate (
Concurrent dispatches of the same tupleTake A and B, two lineages:
The same holds while A sits in Fan-out children don't gate. They inherit the root's stamp, and as running stamped rows they block other lineages. A same-family re-drive while children run is refused, which is fail-closed. Lock keys, normalization and case
So two spellings of one tuple can't both purchase. The service match agrees with Go too: Tenant scope
Runtime (scratch worktree at this SHA, heavy-review-2,
|
|
APPROVED b2ccdef by claude-qa-ui-4 Cold review, judged fail-closed (no duplicate may pass; over-refusal is acceptable).
Runs (testcontainers, GOMAXPROCS=4, -p 2):
Non-blocking:
|
Part of #702. This is PR2 of 4 for Redshift re-drive idempotency, and it does not close the issue. PR1 (#1762, merged) persisted
purchase_executions.first_dispatch_atand passes it to the library asRequestedAt.Why
The library dedupes a Redshift reserved-node buy with
DescribeReservedNodes. It looks for a node that started at or afterRequestedAtminus 5 minutes, with no upper bound. If a second lineage buys the same tuple while an earlier one can still be re-driven, that re-drive could adopt the later node, or refuse as ambiguous. Before Redshift re-drive can be allowed (PR3), a dispatch must refuse when another open lineage could still buy the same tuple.What
FindOpenRedshiftLineageConflictsTx(internal/config/store_postgres_redshift_lineage.go). It finds other executions that could still buy the same tuple (region, node type, term, payment, count). On the account side it uses the row's account, else the rec's account, and a missing account on either side counts as a match (fails closed). A conflicting execution is one of:runningrow other than self, including a parallel run of the same lineage;approved,scheduled,pending,notifiedorpausedrow of another lineage stamped within 24h, judged on the DB clock.The dispatch gate (
internal/purchase/redshift_lineage.go) runs before any provider call for an execution with a Redshift rec, all in one transaction:pg_advisory_xact_lockper tuple, in sorted order;A conflict rolls the stamp back and refuses before submission. A stamp outside the 24h horizon, or a missing stamp on a later attempt, is a plain error, because an earlier attempt may have bought.
Refusal texts are fixed and allowlisted for History. The conflict text does not name the other execution; its id and status go to the server log only.
Unchanged: Redshift re-drive and Retry are still refused.
failedrows join the conflict set together with the guard lift (PR3b).Review
Tests
No migration. A follow-up refactor will make the tuple lock and the plan lock share one advisory-lock key helper.
🤖 Generated with Claude Code