[Draft] chore(api-db): squash the world, and introduce a tool + process for doing so#906
[Draft] chore(api-db): squash the world, and introduce a tool + process for doing so#906chet wants to merge 1 commit into
Conversation
🔐 TruffleHog Secret Scan✅ No secrets or credentials found! Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉 🕐 Last updated: 2026-04-11 22:03:00 UTC | Commit: e01eff6 |
21b004a to
11b1bb4
Compare
…oing so Our 300+ migrations have gotten a little crazy, and I've been wanting to squash it down somehow. This introduces a process for doing so! The idea is we now have a `LAST_SQUASH_VERSION` constant that we track, and any time we want to squash, we: - Run our `squash-migrations` tool, which dumps the current schema and transforms in into a migration-friendly schema. - Bump `LAST_SQUASH_VERSION` to the timestamp in the migration. - Delete the old migrations. When the `carbide-api-migrate` job runs, it will clean out the `_sqlx_migrations` table up until `LAST_SQUASH_VERSION`, and then apply the squash migration, which should be a noop, ensuring all existing tests continue to pass. I also dropped a `README.md` into the migrations directory explaining how to use the tool. This PR has been put together with the tool itself, which includes tests. Signed-off-by: Chet Nichols III <chetn@nvidia.com>
| } | ||
|
|
||
| #[tokio::main] | ||
| async fn main() { |
There was a problem hiding this comment.
Have you seen the xtask crate in crates/xtask? I put it there as a home for the Cargo.toml validator we use (e.g. cargo xtask check-workspace-deps [--fix]), and I kinda figured it'd be the home for any random "repo automation" stuff we want that needs to be written in rust. I got the idea from https://github.com/matklad/cargo-xtask (which is just a document describing the pattern, we don't actually need any dependencies to do it.)
This might be a good fit as an xtask subcommand if you're so inclined.
There was a problem hiding this comment.
Oh yeah, that sounds good. I'll do that (whatever this ends up looking like per the feedback below, at least).
| -- For zero-DPU hosts the states map will be empty, which matches the | ||
| -- code path in the state handler (it immediately skips to HostInit). | ||
|
|
||
| UPDATE machines m |
There was a problem hiding this comment.
What happens if we deploy this branch to an environment that hasn't run this migration yet? I don't see anything in the squashed migration file that does any of this update logic...
Ditto 20260403042500_backfill_rack_id_switches_power_shelves.sql, and basically any file that has UPDATE in it.
I wonder if we should do something like this instead:
- Move all old migrations to
migrations-old - Make the last migration file in
migrations-oldour "barrier" migration - Put the squashed migration in the new
migrationsdir - For any site that has already applied the barrier migration, run the new squashed migration, and do all the stuff you're doing in this PR
- For any site that has not applied the barrier migration yet (ie.
_sqlx_migrations.versionis older than the barrier), have anOLD_MIGRATORthat runs the migrations out ofmigrations-old, run that first, then go to step 4. - We can keep
migrations-oldaround until we're confident everyone has migrated (and it won't be slowing us down for things like unit tests or anything.)
Also, I guess if we're really doing that, we don't actually need to run the squashed migration on any production databases... we can instead run the OLD_MIGRATOR up to the barrier, then skip the big squashed snapshot (maybe inserting a synthetic _sqlx_migrations row), and then we can continue on with the remaining (new) migrations without having to run a (relatively risky) huge squashed migrations row on a mature database.
There was a problem hiding this comment.
Yupppp -- I like it. Let me put some extra thought into this tonight, but I'll make adjustments to it based on your comments, and then pass it back to you.
|
I linked a bug #1077 that I think we could use this tool to fix that. There's an issue where old migrations worked on an older version of PG, but not on a new version so it's impossible to do a DB migration if an old migration is incompatible with a new DB version. |
|
This PR has been inactive for 30 days and will be closed soon. |
|
@chet when you can you pick this back up? |
|
@ajf This week |
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Marking as Draft. Been poking at it today. Plan on putting it back into normal status tomorrow. |
|
Chet let's pick this up for 2.1, I think your approach here is correct. But I don't think we can get to it yet. |
This moves to a single snapshotted .sql file of the whole database schema, and archives old migrations to a pre-squash directory. Compatibility with existing deployments is maintained by splitting into three `sqlx::migrate::Migrator` instances: - One for the pre-squash migrations - One for the squashed migration - One for the post-squash migrations Whether we're an existing deployment or not is determined by the presence of the `_sqlx_migrations` table. For existing deployments, they will migrate through the pre-squash migrations first (skipping any we've already migrated), then migrate through the new migrations directory, intentionally skipping the single squash migration via Migrator::skip. For new deployments, the inverse happens: If we don't see a _sqlx_migrations table, we run the squash migration first, then all the other migrations. If other PR's are open at the time this is under review and are merged, it will not cause any issues: We run the squash migration from crates/api-db/migrations first in its own migrator (or skip it if we're an existing deployment running the legacy migrations), *then* we run every other migration in that directory. So if another migration is added, it will still be run at the correct time. The approach generalizes to multiple squashes: We can do all this again in the future and it's just another entry to add to `MIGRATION_LAYOUT`. Also included is a cargo xtask for performing the squashing, using @chet's PR #906 as a base. ## Related issues #1077 ## Type of Change - [ ] **Add** - New feature or capability - [ ] **Change** - Changes in existing functionality - [ ] **Fix** - Bug fixes - [ ] **Remove** - Removed features or deprecated functionality - [X] **Internal** - Internal changes (refactoring, tests, docs, etc.) ## Breaking Changes - [ ] **This PR contains breaking changes** ## Testing - [X] Unit tests added/updated - [ ] Integration tests added/updated - [X] Manual testing performed - [ ] No testing required (docs, internal refactor, etc.) ## Additional Notes Tested locally via devspace, by deploying the main branch via `devspace deploy -n nico-system`, then checking out this branch, and doing it again, and ensuring the migration worked and looked as expected. Then did the same after starting the database from scratch and just deploying this branch, verifying the migrations table had a single entry.
Description
Our 300+ migrations have gotten a little crazy, and I've been wanting to squash it down somehow, because with the uptick in repo activity, this is just going to keep getting crazier. This introduces a process for doing so!
The idea is we now have a
LAST_SQUASH_VERSIONconstant that we track, and any time we want to squash, we:squash-migrationstool, which dumps the current schema and transforms in into a migration-friendly schema.LAST_SQUASH_VERSIONto the timestamp in the migration.When the
carbide-api-migratejob runs, it will clean out the_sqlx_migrationstable up untilLAST_SQUASH_VERSION, and then apply the squash migration, which should be a noop, ensuring all existing tests continue to pass.I also dropped a
README.mdinto the migrations directory explaining how to use the tool.This PR has been put together with the tool itself via
cargo run -p squash-migrations -- --delete-old.Sets
LAST_SQUASH_VERSIONto20260411215700and introduces the20260411215700_squash_snapshot.sqlsquashed migration.Also: after merging, I'll block any open PRs with pending migrations to make sure the PR gets rebased + the migration timestamp gets bumped before going in.
Tests included in the tool.
Signed-off-by: Chet Nichols III chetn@nvidia.com
Type of Change
Related Issues (Optional)
Breaking Changes
Testing
Additional Notes