Migration numbers are a distributed counter without coordination

aevlampiev1 pts0 comments

Your Migration Numbers Are a Distributed Counter Without Coordination • pgmi

Your Migration Numbers Are a Distributed Counter Without Coordination#<br>What migration-number collisions reveal about identity, ordering, and enforcement.<br>By Alexey Evlampiev<br>Two engineers branch from the same commit on the same Tuesday. Each adds a<br>migration; each picks the next free number — V42. Git merges both files<br>without complaint: two new files, no textual conflict. The migration runner<br>cannot merge them. Two changes now claim the same position.<br>Timestamp versions make that exact collision unlikely, but trade it for a<br>subtler problem: late arrival. A migration stamped earlier can merge after a<br>later one has already run in some environment. Flyway ignores the straggler by<br>default; its outOfOrder<br>setting applies it — &ldquo;a newly discovered version 2.0 will be executed rather<br>than ignored&rdquo; — at the cost of an application history that now differs from a<br>freshly built environment. If you have run migrations on a team<br>of more than two people you have lived some version of this, and lived the<br>fixes: timestamp prefixes, outOfOrder, renumbering commits, &ldquo;announce in<br>Slack before you add a migration.&rdquo;<br>These are not filename problems. They come from three choices every<br>ordered-change system makes: how changes acquire identity , how order is<br>represented, and where the resulting invariants are enforced. Sequential<br>numbers fuse identity and order into a single uncoordinated allocation — each<br>branch reads the same prefix of history, independently allocates the next<br>slot, and git later unions the allocations without checking uniqueness.<br>pgmi takes a deliberately narrow approach to the third choice. It is not a<br>migration framework : it keeps no applied-migrations ledger by default and<br>does not decide what has already run. What it does is expose the computed<br>source plan as an ordinary PostgreSQL relation:<br>SELECT execution_order, sort_key, path<br>FROM pg_temp.pgmi_plan_view<br>ORDER BY execution_order;<br>That is not diagnostic output rendered from an internal plan object. It is<br>the plan. The same deploy.sql that queries those rows is the code that will<br>execute them — so a project can inspect, reject, transform, or execute the plan<br>before any source file runs, and, against a disposable database in CI, before<br>the branch merges.<br>One scope note. This is the authoring-time problem — two branches allocating<br>the same position. It is distinct from runtime coordination of concurrent<br>migrator processes, which tools handle with locks: Flyway and Liquibase<br>serialize concurrent migrations, and pgmi holds a deploy advisory lock and<br>exits with a dedicated code when another deploy is already running. This<br>article is about the first problem.<br>The problem is visible across ecosystems#<br>Liquibase avoids bare sequence numbers as changeset identity.<br>Its FAQ explains why<br>: on separate<br>branches, two people easily pick the same id, and the version-control system<br>&ldquo;won&rsquo;t care that there are two different changesets with the same &lsquo;id&rsquo;.&rdquo; The<br>modern design identifies a changeset by the triple id + author + changelog<br>path, and the docs are explicit<br>that id is an identifier, not an ordering value.<br>Redgate&rsquo;s Flyway documents the same hazard<br>&ldquo;What if a colleague saves a file with the same version number? Flyway will<br>rightfully protest because the order of execution is now ambiguous.&rdquo; On a<br>duplicate version Flyway aborts before applying either migration — safe, and<br>still a merge-day fire drill. The guide&rsquo;s own fixes — timestamp versions,<br>placeholder files, outOfOrder, cherry-picking — it characterizes as<br>workarounds that &ldquo;compromise the value of control.&rdquo;<br>Further down the stack, golang-migrate users have requested a<br>duplicate-version lint (issue #720<br>&ldquo;it is common that they generate migrations with the same version number&rdquo;),<br>and Rails&rsquo; v3.2 guide<br>records that pre-2.1 sequential numbers made it &ldquo;easy for these to clash<br>requiring you to rollback migrations and renumber them&rdquo; — the origin of its<br>2008 switch to timestamps.<br>Identity, ordering, enforcement#<br>Every migration system answers three questions, and keeping them separate is<br>what makes the landscape legible:<br>Identity — what makes two changes the same change or different ones?<br>Ordering — is order a total ordinal, a timestamp, a declared sequence,<br>or a dependency graph?<br>Enforcement — what invariant is checked, when, and by whom?<br>The first two are properties of the data model. The third is a property of<br>workflow: the same duplicate Flyway version can surface in a local validate,<br>in pre-merge CI, or at deploy time, depending on how the team wires it.<br>SystemChange identityOrder representationEnforcement surfaceFlywayUnique versioned scriptTotal version ordervalidate / migrateLiquibaseid + author + pathChangelog sequenceChangelog validation / updateAlembicRevision identifierDependency DAG, topologically sortedHead / merge...

migration version ldquo rdquo numbers identity

Related Articles