Conversation
…e upgrade ## Summary Vendors pgmq-extension/sql/pgmq.sql at v1.13.0 byte-exact. The delta is entirely partitioned-queue work plus one metrics attribute; nothing pgbus calls through Pgbus::Client changes shape. The upgrade migration drops every pgmq function and composite type and re-runs the target schema, which can never alter an existing table. Upstream's 1.13.0 migration does (partitioned queues' msg_id moves to GENERATED BY DEFAULT), so PgmqSchema gains per-hop fixups discovered from lib/pgbus/pgmq_schema/fixups/pgmq_v<VERSION>.sql, and the generated migration applies every fixup between the recorded installed version and the target, after the re-install and before the NOTIFY repair. Fixups must be idempotent: an install with no recorded version gets them all. ## Test Coverage - pgmq_schema_spec: 1.13.0 discovery, install_sql content, fixup_versions, fixups_sql window semantics (nil after, same version, no-fixup hop) - upgrade_pgmq_generator_spec: fixup step present, ordered after install and before the NOTIFY repair, reads the tracking table defensively - pgmq_schema_upgrade_spec (integration): 1.12.0 -> 1.13.0 hop, new create_partitioned signature, default_partition_length in metrics, fixup proven on a partitioned stand-in, ordinary queue untouched, replay safe ## Verification - [x] rubocop (CI command) clean - [x] bare rspec green (4886) - [x] integration green (222) - [x] docs rake lint + rspec green Closes #459
|
Running ultrareview automatically — This PR changes the core upgrade migration path: it introduces fixup version discovery, applies upstream table-level ALTERs (partitioned queues' msg_id identity), and vendors 2,193 lines of new schema SQL.... I'll post findings when complete. |
There was a problem hiding this comment.
Ultrareview completed in 15m 33s
All reported issues were addressed across 10 files
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
CHANGELOG.md [Unreleased] resolved as a union: main's `coalesce:` and concurrency-visibility entries kept alongside this branch's PGMQ 1.13.0 entry under the single `### Added` heading. Claude-Session: https://claude.ai/code/session_017jHYpRCkQkiZHb2etMFH8p
- pgmq_schema.rb: extract `versions_in(dir)` so schema-file and fixup version discovery cannot drift into different rules. - fixups/pgmq_v1.13.0.sql: resolve the queue table by OID via to_regclass instead of matching a formatted name against information_schema. validate_queue_name caps at 47 characters but PostgreSQL truncates identifiers at 63 bytes, so a multibyte queue name could be silently skipped and left at GENERATED ALWAYS — the exact failure the fixup exists to prevent. Header updated: this is now a documented deviation from upstream, not a verbatim copy. - pgmq_schema_spec.rb: the "excludes a fixup newer than the target" example duplicated the hop-with-no-fixup one; it now pins the ceiling against the nil-floor path, which nothing else covered. - pgmq_schema_upgrade_spec.rb: replaying the migration re-runs no fixup (the recorded version has already advanced), so the replay example never proved fixup idempotence. Added an example that re-applies the fixup SQL directly. - CHANGELOG: scope the upgrade instructions to embedded installs and name the extension upgrade path. Claude-Session: https://claude.ai/code/session_017jHYpRCkQkiZHb2etMFH8p
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.
Summary
Vendors PGMQ 1.13.0 and teaches the upgrade migration to carry upstream's table-level fixups.
lib/pgbus/pgmq_schema/pgmq_v1.13.0.sql— byte-exact copy of upstreampgmq-extension/sql/pgmq.sqlat tagv1.13.0(commit32c075bb, blob1fde328bd238e1732b10a02bbe1c8672b66bd973, verified withgit hash-object). Version discovery is a glob, so this alone makes 1.13.0 the install target for:embeddedand the:autofallback.lib/pgbus/pgmq_schema.rb— newfixup_versionsandfixups_sql(after:, upto:), discoveringlib/pgbus/pgmq_schema/fixups/pgmq_v<VERSION>.sqlwith the same glob-and-sort the schema files use.lib/pgbus/pgmq_schema/fixups/pgmq_v1.13.0.sql— upstream's guardedDOblock frompgmq--1.12.0--1.13.0.sql, verbatim.lib/generators/pgbus/templates/upgrade_pgmq.rb.erb— a fourth step between the re-install and the NOTIFY repair, applying every fixup between the version recorded inpgbus_pgmq_schema_versionsand the target.Closes #459.
Why the fixup step exists
The upgrade works by dropping every PGMQ function and composite type and re-running the target version's schema. That reproduces every function and type change — including 1.13.0's new
create_partitionedsignature and themetrics_resultattribute — but it can never touch an existing table. Upstream's 1.13.0 migration alters one: partitioned queues'msg_idmoves fromGENERATED ALWAYStoGENERATED BY DEFAULTso pg_partman'spartition_data_*tooling can move rows out of the default partition. Without a table step that change was silently skipped.The mechanism is per-hop rather than inlined for this release because the generator is version-agnostic and always targets
latest_version; a one-off would have to be hand-removed at the next hop.What does not change
The whole 1.12.0 → 1.13.0 delta is partitioned-queue work plus one metrics attribute. Nothing pgbus calls through
Pgbus::Clientchanges shape:create_partitionedgainspremakeand drops its three-argument form. pgmq-ruby 0.7.2 passes three arguments, which bind to the new signature with the default.metrics_resultgainsdefault_partition_length.PGMQ::Metricsbuilds from named columns, so the extra one is ignored.msg_idis a plainBIGINT NOT NULL.No pgmq-ruby bump (0.7.2 is current), no
Pgbus::Clientchange, no workflow change —dependency-watch.ymlderives the vendored version from the same glob andmain.ymlinstalls with no version argument.Test plan
bundle exec rspec spec/pgbus/pgmq_schema_spec.rb spec/pgbus/pgmq_versions_task_spec.rb spec/generators— green (41 + 206)PGBUS_DATABASE_URL=... bundle exec rspec spec/integration/pgmq_schema_upgrade_spec.rb— green (14), rewritten for the 1.12.0 → 1.13.0 hopbundle exec rspec(bare, full) — greenPGBUS_DATABASE_URL=... bundle exec rspec spec/integration(non-streams) — greenbundle exec rubocop app benchmarks config gemfiles lib spec Gemfile Rakefile pgbus.gemspec— no offensescd docs && bundle exec rake lint && bundle exec rspec— greengit hash-object lib/pgbus/pgmq_schema/pgmq_v1.13.0.sqlmatches the upstream blobrake pgbus:pgmq:statusreports the update,rails generate pgbus:upgrade_pgmq+rails db:migratemoves to 1.13.0, and NOTIFY-gated wakeups still fire afterwards.New integration coverage proves the fixup end to end: that dropping and re-creating the functions alone leaves
msg_idatALWAYS, that the full migration moves it toBY DEFAULT, that an ordinary queue is left alone, and that replaying the migration is safe.Deviations & judgment calls
Discoveries the plan did not know
pgbus.gemspecneeded no change. It selects files withgit ls-filesfiltered onlib/, so the newfixups/subdirectory ships once committed. Verified before relying on it rather than assumed.GENERATED ALWAYSin 1.13.0. Only the partitioned path moved toBY DEFAULT. My first integration assertion expected the whole schema to have moved and failed; the corrected example now pins the more useful property — that the fixup is scoped bypgmq.meta.is_partitionedand does not touch ordinary queues.Judgment calls
is_partitionedinpgmq.meta. The fixup's loop selects purely on that flag, so the stand-in drives the identical code path without adding an extension dependency to CI.pgmq--1.12.0--1.13.0.sql(theDROP FUNCTION, the newcreate_partitioned, theALTER TYPE, the newmetrics()) is already produced by drop-and-reapply; carrying it twice would fail on the second run.Review round (cubic, 10 threads)
Five threads landed on
lib/pgbus/pgmq_schema/pgmq_v1.13.0.sql. That file is a byte-exact copy of upstream (git hash-object=1fde328b…), so all five were declined: patching it forks pgbus from upstream and breaks the verification that is the file's whole contract. Four of the five flag constructs that are byte-identical inpgmq_v1.12.0.sql, shipped in v0.12.0 — pre-existing upstream behaviour, not introduced by this hop. The fifth (default_partition_length) is genuinely new here but is still upstream's code; pgbus never creates partitioned queues, so it never runs.Five were accepted, in
57ecb1b:information_schema.columns.table_nameagainst a formatted name, butvalidate_queue_namecaps the queue at 47 characters while PostgreSQL truncates identifiers at 63 bytes — so a multibyte name could be silently skipped and left atGENERATED ALWAYS, the exact failure the fixup exists to prevent. Nowto_regclass+pg_attribute.attidentity. This makes the fixup a deliberate deviation from upstream rather than a verbatim copy, so its header no longer claims otherwise.fixups_sqlreturns""and the fixup SQL never ran twice. Added an example that re-applies it directly, which is what actually pins the load-bearing idempotence invariant.available_versionsandfixup_versionsnow share a privateversions_in(dir), so discovery rules cannot drift.nil-floor path, which nothing covered.ALTER EXTENSION pgmq UPDATE).Declined as out of scope: making the generator reject extension-tracked databases. The drop-and-reinstall path predates this PR (#364) — this PR adds only the fixup step — and it fails loudly rather than silently, since PostgreSQL refuses to drop extension-owned functions. Worth a follow-up issue.
Summary by cubic
Vendors PGMQ v1.13.0 and adds a table-fixup step to the generated upgrade migration so upstream's 1.13.0 table change actually lands. The upgrade previously dropped every pgmq function and composite type and re-ran the target version's schema, which reproduces all function and type changes but never alters an existing table; the migration now applies every fixup shipped for versions between the recorded installed version and the target.
What changes
create_partitionedgainspremake(dropping its three-argument form),metrics_resultgainsdefault_partition_length, and new partitioned queues usemsg_id … GENERATED BY DEFAULTinstead ofGENERATED ALWAYS.lib/pgbus/pgmq_schema/fixups/; version discovery now sharesversions_in(dir)with schema files so the two can't drift.to_regclassinstead of comparing formatted names, so multibyte queue names aren't silently skipped; this is a documented deviation from upstream's guard.Pgbus::Clientchanges shape, so nopgmq-rubybump is needed.Migration
:embeddedand versionless:autoinstalls get 1.13.0 automatically.:embeddedinstalls: runrake pgbus:pgmq:status, thenrails generate pgbus:upgrade_pgmqandrails db:migrate(orrails db:migrate:pgbuson a separate-database install).:extensioninstalls upgrade viaALTER EXTENSION pgmq UPDATEinstead.Integration coverage proves the fixup end to end: dropping and re-creating the functions alone leaves
msg_idatALWAYS, the full migration moves it toBY DEFAULT, an ordinary queue is untouched, and replaying the migration is safe. Closes #459.Written for commit 57ecb1b. Summary will update on new commits.