Repository navigation
cmd: add tester migrate and make startup migrations optional for a PRE_DEPLOY job (MARSOHS-1643) - #13
Merged
Merged
Conversation
| "log" | ||
|
|
||
| "github.com/digitalocean/tester/db" | ||
| "github.com/jackc/pgx/v4/pgxpool" |
There was a problem hiding this comment.
Use github.com/jackc/pgx/v5 or newer instead of other postgres driver libraries
🥳 Fixed in commit f251d49 🥳
Collaborator
Author
There was a problem hiding this comment.
ElanHasson
marked this pull request as ready for review
September 21, 2026 19:34
ElanHasson
force-pushed
the
predeploy-migrate
branch
from
September 21, 2026 19:36
cf77082 to
0af5b99
Compare
tester migrate and make startup migrations optional for a PRE_DEPLOY job (MARSOHS-1479)tester migrate and make startup migrations optional for a PRE_DEPLOY job (MARSOHS-1643)
ElanHasson
marked this pull request as draft
September 21, 2026 19:38
ElanHasson
force-pushed
the
predeploy-migrate
branch
from
September 21, 2026 19:50
0af5b99 to
424c4ed
Compare
ElanHasson
added a commit
that referenced
this pull request
Sep 21, 2026
Semgrep flags any new file importing github.com/jackc/pgx/v4 ("Use
github.com/jackc/pgx/v5 or newer instead of other postgres driver
libraries"), which blocks #13 (cmd/tester/migrate.go). Move the whole repo
to pgx v5 and tern v2 rather than suppressing the finding.
API changes:
- github.com/jackc/pgx/v4 -> /v5, pgxpool and pgconn likewise
(github.com/jackc/pgconn is now github.com/jackc/pgx/v5/pgconn).
- github.com/jackc/tern/migrate -> github.com/jackc/tern/v2/migrate.
NewMigrator, AppendMigration, Migrate, MigrateTo, GetCurrentVersion and
OnStart are unchanged in shape; v2 just takes a v5 *pgx.Conn.
- pgxpool.Connect is gone; pgxpool.New connects lazily, so serve (and the
test harness) now Ping after constructing the pool to keep a bad DSN
failing at startup.
- github.com/lib/pq dropped: pq.Array was only used for runs.args
(varchar[]), which v5 encodes and scans as []string natively.
- pgx v5 encodes a nil slice/pointer for a json/jsonb parameter as SQL NULL
where v4 sent JSON null. tests.result, tests.logs and runs.meta are jsonb
NOT NULL and the runner produces nil Logs for a test with no output, so
those columns are now pre-marshalled with encoding/json (db.jsonb) to
keep the v4 wire behaviour. TestPG_AddTest_NoLogs pins this; without the
helper TestPG_ListRunSummariesInRange fails with the NOT NULL violation.
Indirect jackc modules (pgtype, pgproto3, pgio, chunkreader, puddle v1) drop
out of go.mod. .github/dependabot.yml's github.com/jackc/* group already
covers the v5/v2 paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
…PRE_DEPLOY job (MARSOHS-1643) `tester serve` runs the tern migrations at startup, which means they run inside the web container's health-check window on App Platform. A slow migration (e.g. an index build on the 15 GB tests table) makes the deploy look unhealthy and roll back mid-migration; multiple web replicas serialize on the advisory lock; and the worker component rolls independently, so it can start against a not-yet-migrated schema. A PRE_DEPLOY job runs once, to completion, before any component of the new deployment starts. - `tester migrate`: connects with --pg-dsn / MIGRATE_PG_DSN (falling back to SERVE_PG_DSN so the job can reuse the web env), applies pending migrations, exits 0, non-zero on failure. - Every migration tern applies is now logged (Migrator.OnStart), for both `migrate` and `serve`. - New `serve --migrate-on-start` flag / SERVE_MIGRATE_ON_START env (default true, preserving current behaviour). When false, `serve` skips migrating and instead calls the new `(*db.PG).CheckSchema`, exiting non-zero with the current and expected versions if the schema is behind, so a misordered deploy fails fast rather than serving a stale schema. A newer schema is tolerated so the image can be rolled back. `serve` uses the concrete *db.PG, so the db.DB interface and mock are unchanged. A flag rather than a config.json field so the web component can be switched over with an app-spec env edit, without rebuilding the e2e image. - README: document `tester migrate`, `--migrate-on-start`, an App Platform PRE_DEPLOY job snippet and the rollout order. - Tests: TestPG_CheckSchema (current / behind / ahead) and TestServe_migrateOnStart (default / env / flag precedence). The app-spec change in digitalocean/e2e is a separate, manual step. Co-authored-by: Cursor <cursoragent@cursor.com>
ElanHasson
force-pushed
the
predeploy-migrate
branch
from
September 21, 2026 19:55
424c4ed to
f251d49
Compare
ElanHasson
marked this pull request as ready for review
September 21, 2026 20:01
ElanHasson
added a commit
that referenced
this pull request
Sep 21, 2026
* deps: upgrade to pgx v5 and tern v2 (MARSOHS-1643)
Semgrep flags any new file importing github.com/jackc/pgx/v4 ("Use
github.com/jackc/pgx/v5 or newer instead of other postgres driver
libraries"), which blocks #13 (cmd/tester/migrate.go). Move the whole repo
to pgx v5 and tern v2 rather than suppressing the finding.
API changes:
- github.com/jackc/pgx/v4 -> /v5, pgxpool and pgconn likewise
(github.com/jackc/pgconn is now github.com/jackc/pgx/v5/pgconn).
- github.com/jackc/tern/migrate -> github.com/jackc/tern/v2/migrate.
NewMigrator, AppendMigration, Migrate, MigrateTo, GetCurrentVersion and
OnStart are unchanged in shape; v2 just takes a v5 *pgx.Conn.
- pgxpool.Connect is gone; pgxpool.New connects lazily, so serve (and the
test harness) now Ping after constructing the pool to keep a bad DSN
failing at startup.
- github.com/lib/pq dropped: pq.Array was only used for runs.args
(varchar[]), which v5 encodes and scans as []string natively.
- pgx v5 encodes a nil slice/pointer for a json/jsonb parameter as SQL NULL
where v4 sent JSON null. tests.result, tests.logs and runs.meta are jsonb
NOT NULL and the runner produces nil Logs for a test with no output, so
those columns are now pre-marshalled with encoding/json (db.jsonb) to
keep the v4 wire behaviour. TestPG_AddTest_NoLogs pins this; without the
helper TestPG_ListRunSummariesInRange fails with the NOT NULL violation.
Indirect jackc modules (pgtype, pgproto3, pgio, chunkreader, puddle v1) drop
out of go.mod. .github/dependabot.yml's github.com/jackc/* group already
covers the v5/v2 paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
* cmd: add `tester migrate` and make startup migrations optional for a PRE_DEPLOY job (MARSOHS-1643) (#13)
`tester serve` runs the tern migrations at startup, which means they run
inside the web container's health-check window on App Platform. A slow
migration (e.g. an index build on the 15 GB tests table) makes the deploy
look unhealthy and roll back mid-migration; multiple web replicas serialize
on the advisory lock; and the worker component rolls independently, so it
can start against a not-yet-migrated schema. A PRE_DEPLOY job runs once, to
completion, before any component of the new deployment starts.
- `tester migrate`: connects with --pg-dsn / MIGRATE_PG_DSN (falling back to
SERVE_PG_DSN so the job can reuse the web env), applies pending
migrations, exits 0, non-zero on failure.
- Every migration tern applies is now logged (Migrator.OnStart), for both
`migrate` and `serve`.
- New `serve --migrate-on-start` flag / SERVE_MIGRATE_ON_START env (default
true, preserving current behaviour). When false, `serve` skips migrating
and instead calls the new `(*db.PG).CheckSchema`, exiting non-zero with
the current and expected versions if the schema is behind, so a misordered
deploy fails fast rather than serving a stale schema. A newer schema is
tolerated so the image can be rolled back. `serve` uses the concrete
*db.PG, so the db.DB interface and mock are unchanged. A flag rather than
a config.json field so the web component can be switched over with an
app-spec env edit, without rebuilding the e2e image.
- README: document `tester migrate`, `--migrate-on-start`, an App Platform
PRE_DEPLOY job snippet and the rollout order.
- Tests: TestPG_CheckSchema (current / behind / ahead) and
TestServe_migrateOnStart (default / env / flag precedence).
The app-spec change in digitalocean/e2e is a separate, manual step.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Stacked on #15 (pgx v5 / tern v2 upgrade) — merge that first; this PR's diff against
mainincludes it until then.Story: MARSOHS-1643 (under epic MARSOHS-1585).
Motivation
tester serveruns the tern migrations at startup, i.e. inside the web container's health-check window on App Platform:teststable) makes the deploy look unhealthy and roll back mid-migration;workercomponent rolls independently, so it can start against a not-yet-migrated schema.A
PRE_DEPLOYjob runs once, to completion, before any component of the new deployment starts.What changed
tester migrate(cmd/tester/migrate.go): connects with--pg-dsn/MIGRATE_PG_DSN, falling back toSERVE_PG_DSNso the job can reuse the web service's env verbatim; applies pending migrations; exits 0 (non-zero on failure). It does not readconfig.json— the DSN is the only thing it needs (in this repo the DSN is aserveflag/env, not a config-file field).Migrator.OnStartis wired in(*db.PG).migrator, so bothmigrateandservelog every migration they apply (db: applying migration 5 "..." (up)).serve --migrate-on-startflag /SERVE_MIGRATE_ON_STARTenv (bool, default true, so current behaviour is unchanged; same pattern as--pg-dsn/SERVE_PG_DSN). Whenfalse,serveskipsInitand calls the new(*db.PG).CheckSchema, which compares tern's current version tolen(pgMigrations)and fails withdatabase schema is at version N, this binary expects M: runtester migrate`` if behind — so a misordered deploy fails fast rather than serving a stale schema. A newer schema is tolerated so the image can be rolled back. It is a flag rather than aconfig.jsonfield so the `web` component can be switched over with an app-spec edit, no e2e image rebuild. `serve` uses the concrete `*db.PG`, so the `db.DB` interface and `db_mock.go` are unchanged.tester migrate,--migrate-on-start, an App PlatformPRE_DEPLOYsnippet, and the rollout order.TestPG_CheckSchema(current → rolled back one migration → re-migrated → ahead) against real Postgres;TestServe_migrateOnStart(default true, env overrides default, flag overrides env).Rollout order
--migrate-on-startat its default (true). No behaviour change.PRE_DEPLOYjob to the e2e app spec. Both the job and the server now migrate; the server's is a no-op.webcomponent, setSERVE_MIGRATE_ON_START=falseinenvs(orrun_command: tester serve --migrate-on-start=false ...). No image rebuild. The server now only verifies the schema.App spec snippet (goes in
digitalocean/e2e, separate manual step, not in this PR)The binary is
/bin/testerin the image (Dockerfile), invoked the same wayserve/runare today.Verification
gofmt -l .,go vet ./...,go generate ./... && git diff --exit-code db/db_mock.go,PG_DSN=... go test -race ./...all pass locally againstpostgres:16. Also exercised the built binary:serve --migrate-on-start=falseandSERVE_MIGRATE_ON_START=false serveagainst an empty DB both exit 1 with the version message;migrate(viaSERVE_PG_DSN) applies 5 migrations and exits 0;servewith the env set then starts; defaultserveon a fresh DB applies the 5 migrations itself.