‹ BackHN Continuity

Thread

Is your Postgres migration safe or not safe?

138 points · 45 comments · vira28

  1. orf · · focus · HN ↗
    These kinds of rule-based migration safety checks are simple, but hardly complete.

    The problem is that some migration safety depends on the state of the database, which isn’t represented in the DDL statement alone. For example, altering a column type is either a no-op or an exclusive locked table rewrite depending on the original type of the column.

    There are other footguns that can happen if the column you’re altering is a foreign key, where multiple tables can be locked.

    I went down a rabbit hole a few years ago and built a system[1] to introspect a given migration against a live schema, and actually let Postgres tell you what it’s doing[2].

    It would be great to have better built-in support for this (EXPLAIN for DDL statements?), but this direction feels safer and more accurate than static rulesets.

    Safety also depends on the size/activity of a table being altered (i.e rewriting an empty table is fine). Having an accurate representation of the locks and actions performed by the database lets you integrate with production metrics to actually determine real-world safety across a fleet of databases, rather than guessing.

    1. <a href="https:&#x2F;&#x2F;github.com&#x2F;orf&#x2F;locksmith" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;orf&#x2F;locksmith

    2. <a href="https:&#x2F;&#x2F;github.com&#x2F;orf&#x2F;locksmith&#x2F;blob&#x2F;f8798c6ee92bfae10d416c49aae33bc4afaaabf1&#x2F;crates&#x2F;locksmith&#x2F;src&#x2F;oracle.rs#L34" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;orf&#x2F;locksmith&#x2F;blob&#x2F;f8798c6ee92bfae10d416c...

    1. grogers · · focus · HN ↗
      I would go further than this and argue that most bugs during database migrations happen because of mismatched application behavior with the action of the migration, not because the DDL was wrong. E.g. removing something that was still being relied on by the application, or starting to backfill data to a new column before the application is fully writing it. The most insidious version of this is where one application server doesn&#x27;t have it&#x27;s code updated (or comes back from the dead, etc) and causes the problem.

      At a previous job what I did to prevent that was to have a special DB table that would signal what capabilities the database has, and the code would read that table and compare to its own requirements. If a capability required by the database was not present in the code (e.g. code not updated for a new feature) the code would refuse to make any writes to the DB and error all incoming requests. Likewise if a capability required by the code was missing from the database (e.g. code deployed too soon and database migration not run yet) it again would refuse requests. Before setting a feature to required in the DB and preforming the migration with feature flags, we could check all known application servers were reporting compatibility with the new feature (if any were down or not reporting at the time, they will be blocked in the next step - prioritizing safety over liveness)

      1. necovek · · focus · HN ↗
        I believe there are patterns that always work, but might not be optimal for all circumstances.

        Eg. you could have a mirror table that you keep in sync with triggers without any constraints or foreign keys, do the migration on it, and then switch them around when ready.

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.