fix: make lifecycle job teardown atomic - #204
Draft
NikolayS wants to merge 1 commit into
Draft
Conversation
This was referenced Jul 28, 2026
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.
Fixes #203.
Contract decision
Lifecycle functions now raise and roll back when they cannot complete managed pg_cron work. A warning or partial-success row would still be unsafe because
rebuild_partitions()anduninstall()consumeash.stop()internally; an uncaught error gives all four entry points one honest, statement-atomic contract.ash.stop()pre-resolves genuine absence, unschedules exact job IDs, requirescron.unschedule()to return true, and emits aremovedrow only after proven deletion (with the real job ID).ash.rebuild_partitions()andash.uninstall()inherit that error, so config changes, earlier unschedules, DDL/data changes, and schema removal roll back together.ash.start()applies the same exact-ID/true-result rule to rollup replacement. Existing sampler/rotation jobs have schedule, command, target database, and active state repaired.ashschema owner. This closes the cross-superuser variant where role B bypasses owner-only ACLs, misses role A's jobs, and drops the schema. Visible foreign-owned managed jobs targeting the installation database make teardown fail closed with the job and owner named.The catalog comments, README, release notes, and the rollup blueprint now describe this contract; the blueprint no longer prescribes
EXCEPTION WHEN OTHERS THEN NULL.RED
Captured before the fix with the issue's locked-row reproduction:
Artifact:
/tmp/pgash-203-red-TunI9x/results.tsv(log line 2298 in/tmp/pgash-203-red-TunI9x/17_fresh-install.log).GREEN
The exact deterministic workflow assertion passed on every supported surface major, including the row-lock rollback, real-ID/idempotency checks, inactive/drifted-job repair, cross-superuser rejection, and foreign-owned-job fail-closed probe:
Complete PG17 release gate:
Machine-readable TSV:
/tmp/pgash-203-owner-all-D4Izt0/results.tsv.Also green:
test_release_stamp.py(17),test_ci_step_script.py(7), extracted-stepbash -n,git diff --check, and overlay discovery (2.0-beta1,devel/sql/ash-install.sql).Further lifecycle-result sites found
These remain intentionally deferred; they are separate operational-result or frozen-migration contracts, but they share the same family of misleading SQL success and should be tracked:
sql/migrations/ash-1.1-to-1.2.sql:21-30catches every sampler-command update error and does nothing. A lock/permission failure can leave the old command while the migration continues.sql/migrations/ash-1.2-to-1.3.sql:2612-2630repeats that pattern aroundcron.alter_job(). Both are frozen legacy migration legs, so this PR does not rewrite them casually.devel/sql/ash-install.sql:1590-1652,1680-1682:ash.rotate()returnsfailed: ...text for rollup contention/failure/incompleteness and truncate lock timeout, so pg_cron records SQL success (the known B2 result-contract family).devel/sql/ash-install.sql:3541-3546,3561-3566:ash.rollup_minute()returns0both when caught up and when rollup/sampler locks are busy; callers cannot distinguish no work from no progress.devel/sql/ash-install.sql:3905-3910:ash.rollup_cleanup()returns a skipped string on lock contention; a direct caller sees it, but pg_cron still records SQL success.ash.stop()returns an external-scheduler reminder, butash.uninstall()consumes that row and drops the schema. It truthfully counts zero pg_cron removals, but the reminder is lost; external scheduler ownership needs its own policy.Landing coordination
This branch is rebased on current
origin/main(87c22a3) and uses the post-#179 development-overlay policy: releasedsql/ash-install.sqland frozen migrations are unchanged; the complete next payload isdevel/sql/ash-install.sql.PR #201 also adds that complete overlay and already contains the same overlay-aware config-ordinal chain split, so landing #201 first will create an add/add overlap. Rebase this PR after #201 and apply the lifecycle delta on top of #201's copy-reviewed development installer; keep #201's wording where unrelated.
PR #200 should then promote the composed #201 + #203 development payload while retaining #200/#202's transaction-local installer wrapper and #200's release identity/RELEASE_NOTES organization. Port the #203 lifecycle note deliberately rather than letting either full-file version overwrite the other.