preflight: wait for the subscription's slot to be released before dropping it - #140
Conversation
…pping it
TestCheckCopySwapShapeRefusesSubscriptionTarget drops the publisher-side
replication slot in its cleanup right after disabling and dropping the
subscription. ALTER SUBSCRIPTION ... DISABLE only signals the apply worker
to exit; the publisher's walsender keeps the slot active until the worker's
connection closes, so pg_drop_replication_slot raced it and failed with
SQLSTATE 55006 ("replication slot is active for PID") on any major.
The cleanup now polls pg_replication_slots under a named deadline until the
slot is inactive, then drops it.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
🤖 1/2: adversarial correctness review of 0 blocking, 1 non-blocking. The diagnosis is right, and the fix waits on the right signal. Non-blocking1. The poll reports a failed read as "the walsender should release the slot".
assert.EventuallyWithT(t, func(c *assert.CollectT) {
var active bool
err := publisher.QueryRow(ctx,
`SELECT active FROM pg_replication_slots WHERE slot_name = 'sub_applied'`).Scan(&active)
if !assert.NoError(c, err, "read the slot") {
return
}
assert.False(c, active, "the apply worker's walsender still holds the slot")
}, slotReleaseDeadline, 50*time.Millisecond)The test passes with this change, three of three runs. With the same wrong slot name, it fails with Verified
This review was generated by Claude Code (claude-opus-5-5). |
|
🤖 2/2: OSS adoption and integration ease, at This is a test-only change, so it adds no API for an importer to adopt and changes no behavior an importer depends on. What it does is make RF-2's subscription refusal test reliable on every major. That is the evidence an importer such as SchemaBot relies on when it trusts preflight to refuse a table that a subscription applies into. 1. Carry this race into the slot lifecycle manager when ST-3 lands. No code outside the tests calls This review was generated by Claude Code (claude-opus-5-5). |
aparajon
left a comment
There was a problem hiding this comment.
🤖 Approving 7d5b15b with 0 blocking findings. The fix waits on the right signal, and I reproduced the 55006 race and its fix in a throttled container. The 1/2 comment has one non-blocking finding: the poll reports a failed read as a slot that is still held. The 2/2 comment has one integration note for ST-3's slot drop.
This stamp was left by Claude Code (claude-opus-5-5).
|
🤖 Adversarial review response — created by Kiran's code review agent (Amp, Claude Opus 4.6) — pull/140, follow-up commit Verdict: no blocking findings; the one correctness note is fixed as proposed, and the integration-lens note is tracked as an internal follow-up on the slot-lifecycle row.
Source: block/pg-sprite#140, review comments 5927064869 and 5927066372 and review 5376391424 at head |
Why
TestCheckCopySwapShapeRefusesSubscriptionTarget(added in #135) fails intermittently in CI on any PostgreSQL major — seen on 17/18 in the #135 merge run onmainand on 15 in #137's run:The cleanup disables and drops the subscription, then immediately runs
pg_drop_replication_slot('sub_applied')on the publisher.ALTER SUBSCRIPTION ... DISABLEonly signals the apply worker to exit; the publisher's walsender holds the slot active until that worker's connection closes, so the drop races the worker.What
The cleanup polls
pg_replication_slots.activefor the slot under a named deadline until it is released, then drops it. The subscription is still detached from its slot first, so the drop still needs no publisher connection. Test-only change; no engine behavior touched.Verification
scripts/test-flaky.sh TestCheckCopySwapShapeRefusesSubscriptionTarget 20 ./pkg/preflight/— 20/20 with-race.make lint— 0 issues.