Skip to content

Switch migrator to orchestrator and manage downstream migrations#2094

Open
iplay88keys wants to merge 6 commits into
mainfrom
iplay88keys/migrations-improvements-pt-3
Open

Switch migrator to orchestrator and manage downstream migrations#2094
iplay88keys wants to merge 6 commits into
mainfrom
iplay88keys/migrations-improvements-pt-3

Conversation

@iplay88keys

@iplay88keys iplay88keys commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

Restructures the DB migration machinery from two hardcoded tracks (core, vector) into a single orchestrator that applies an ordered list of Source descriptors. Downstream consumers register their own Sources instead of shipping a duplicate runner, so track ordering and failure handling stay centralized in one place.

This is the first step toward broader migration rollback tooling.

What changed

  • Source descriptor + orchestrator: new Source{Name, Schema, TrackingTable, FS, Dir, PreCheck} and RunUp(ctx, url, []Source). BuiltinSources(vectorEnabled) builds the built-in set: core always, vector (with the pgvector PreCheck) when enabled.
  • Conditional registration, not skip predicates: the vector track is gated by whether its Source is registered rather than a flag inside the runner, so vectorEnabled no longer leaks into the orchestrator contract.
  • Prechecks run up front: all PreChecks run before any source is applied, preserving the existing fail-fast pgvector behavior (verified before core runs).
  • Compensating rollback across N sources: if a later source fails, already-applied sources roll back to their pre-run versions in reverse order, each preserving the prevVersion == 0 guard (don't roll a freshly-installed source back to 0). This generalizes today's "roll core back if vector fails". Failed compensating rollbacks are surfaced via errors.Join rather than log-only.
  • Schema isolation (Source.Schema != ""): a non-empty schema scopes the track. The orchestrator creates the schema (CREATE SCHEMA IF NOT EXISTS), pins search_path on the DSN, and scopes the tracking table via migratepgx.Config.SchemaName. Schema names are validated (lowercase identifier, so the quoted CREATE SCHEMA and the case-folded search_path can't diverge) and quoted. Built-in tracks use Schema == "", which resolves to the connection default (public), unchanged from today.
  • Source validation: rejects two sources colliding on the same (schema, tracking table), including the case where Schema == "" resolves to a schema another source names explicitly (checkResolvedSchemaCollisions, run with a live connection).
  • Extension-point change: app.Start's MigrationRunner DI callback is removed in favor of extraSources []migrations.Source; built-in sources run first, then downstream extras in registration order.

Breaking change

app.Start(getExtensionConfig, migrationRunner) becomes app.Start(getExtensionConfig, extraSources []migrations.Source). The MigrationRunner type is removed; downstream consumers register sources instead, and migrate to that in the same release. cmd/controller/main.go passes nil (a valid empty source list).

Behavior preserved

Same tracking tables (schema_migrations, vector_schema_migrations), same ahead-of-binary compatibility mode, same dirty-and-ahead hard error, same ErrNoChange no-op, same prevVersion == 0 rollback-skip guard, same fail-fast pgvector check. golang-migrate's pgx driver still checks out a single dedicated connection for the session-scoped advisory lock; the pool is not capped because the driver pins lock and migration work to that connection.

Testing

  • Manual upgrade test from 0.9.10
  • New table-driven + testcontainers coverage: multi-source ordering, compensating rollback across three sources (incl. the prev == 0 guard), schema-scoped source, precheck-runs-before-any-apply, source-collision validation, schema-name validation, withSearchPath, and empty/nil no-op.
  • Existing core/vector scenarios adapted to the new signature; all prior behaviors retained.
  • go build, go vet, and the container-free tests pass; the testcontainers suite requires Docker.

iplay88keys and others added 5 commits June 26, 2026 08:22
Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
…s-improvements-pt-3

Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
@iplay88keys iplay88keys marked this pull request as ready for review July 2, 2026 21:46
Copilot AI review requested due to automatic review settings July 2, 2026 21:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the database migration system from a hardcoded “core/vector” runner into a general multi-source orchestrator ([]migrations.Source), enabling downstream consumers to register additional migration tracks while keeping ordering, prechecks, and compensating rollback centralized.

Changes:

  • Introduces migrations.Source + migrations.RunUp(ctx, url, []Source) orchestration with upfront prechecks, schema scoping, collision detection, and multi-source compensating rollback.
  • Updates app startup and test helpers to pass built-in sources + optional downstream-registered sources instead of injecting a custom runner.
  • Expands/updates migration tests to cover multi-source ordering, rollback across N sources, schema scoping, and validation behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
go/core/test/upgrade/roundtrip_test.go Updates upgrade test to call the new context-aware RunUp with BuiltinSources.
go/core/pkg/migrations/runner.go Replaces the old runner with a Source-based orchestrator, schema scoping, collision validation, and generalized rollback/error handling.
go/core/pkg/migrations/runner_test.go Adapts existing tests and adds new coverage for multi-source orchestration, schema scoping, prechecks, and validations.
go/core/pkg/app/app.go Changes app.Start to accept extraSources []migrations.Source and runs built-ins + extras via the orchestrator.
go/core/internal/dbtest/dbtest.go Updates DB test helper to use the new RunUp(ctx, url, BuiltinSources(...)) signature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread go/core/pkg/migrations/runner.go
Comment thread go/core/pkg/migrations/runner.go
Comment thread go/core/pkg/migrations/runner.go Outdated
Comment thread go/core/pkg/migrations/runner.go Outdated
Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants