docs(deployment): rewrite migration prose for goose adoption
Update the deployment book and glossary to reflect the goose-based schema migration flow shipped in 12b2f9d/0f7450a: - ch07: clarify startup probe assumes migrations ran out-of-band - ch08: drop AutoMigrate-with-advisory-lock prose; describe goose Job - ch12: pod startup checks goose_db_version, no longer runs migrations - ch14: document the Job→wait→roll deploy gate and how to debug failures - ch16: add "Migrate Job fails during deploy" + "Schema precondition failed" failure modes - ch17: new runbook entries §26 (run migrations manually), §27 (recover from failed/dirty migration), §28 (bootstrap goose on fresh clone) - ch19: postscript on §13 noting MigrateWithLock approach is superseded - ch20: mark "Migration Job for schema changes" task done - glossary: add `goose` and `goose_db_version`; flag AutoMigrate as tests-only - references: add goose links; flag AutoMigrate as tests-only
This commit is contained in:
@@ -428,10 +428,94 @@ KUBECONFIG=~/.kube/honeydue.yaml bash deploy-k3s/scripts/03-deploy.sh --skip-bui
|
||||
```
|
||||
|
||||
The pooler runs in transaction mode so any session-scope feature
|
||||
(LISTEN/NOTIFY, session advisory locks for migrations) auto-falls
|
||||
through to direct via `MigrateWithLock` opening its own connection.
|
||||
But if you ever add session-level features in the data path, they'll
|
||||
need the direct endpoint.
|
||||
(LISTEN/NOTIFY, session advisory locks) won't work over it. Migrations
|
||||
already handle this — the migrate Job script strips `-pooler` from
|
||||
`DB_HOST` before invoking goose. If you add new session-level features
|
||||
in the data path, they'll need the same workaround.
|
||||
|
||||
## 26. Run migrations manually (rare)
|
||||
|
||||
Day-to-day, migrations run as part of every `03-deploy.sh`. But
|
||||
sometimes you want to apply or inspect them outside a deploy:
|
||||
|
||||
```bash
|
||||
# Direct-endpoint DSN (goose's advisory lock won't survive the pooler)
|
||||
DB_PASS=$(kubectl -n honeydue get secret honeydue-secrets \
|
||||
-o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d)
|
||||
export DATABASE_URL="host=ep-floral-truth-amttbc5a.c-5.us-east-1.aws.neon.tech \
|
||||
port=5432 user=neondb_owner password=$DB_PASS \
|
||||
dbname=honeyDue sslmode=require"
|
||||
|
||||
# What's pending? (read-only; safe to run anytime)
|
||||
make migrate-status
|
||||
|
||||
# Apply pending migrations (or `goose -dir migrations postgres "$DATABASE_URL" up`)
|
||||
make migrate-up
|
||||
|
||||
# Roll back the most recent migration
|
||||
make migrate-down
|
||||
|
||||
# Scaffold a new migration file
|
||||
make migrate-new name=add_widget_count_to_residences
|
||||
# → migrations/000002_add_widget_count_to_residences.sql
|
||||
# Edit, then `make migrate-up` to test, then commit.
|
||||
```
|
||||
|
||||
To run goose from inside the cluster (e.g., to bypass a network policy
|
||||
that blocks Neon from your laptop), use the migrate Job manifest as a
|
||||
one-shot:
|
||||
|
||||
```bash
|
||||
# Re-runs the latest migrate Job with whatever args you need
|
||||
kubectl -n honeydue delete job honeydue-migrate --ignore-not-found
|
||||
sed "s|image: IMAGE_PLACEHOLDER|image: $(kubectl -n honeydue get deploy api -o jsonpath='{.spec.template.spec.containers[0].image}')|" \
|
||||
deploy-k3s/manifests/migrate/job.yaml | kubectl apply -f -
|
||||
kubectl -n honeydue wait --for=condition=complete --timeout=5m job/honeydue-migrate
|
||||
kubectl -n honeydue logs job/honeydue-migrate
|
||||
```
|
||||
|
||||
## 27. Recover from a failed/dirty migration
|
||||
|
||||
If `goose up` fails partway through, the migration file's transaction
|
||||
rolls back and `goose_db_version` reflects the last *complete*
|
||||
version. Goose marks no row as "dirty" — that's a golang-migrate
|
||||
concept. So recovery is just: fix the migration file, re-run.
|
||||
|
||||
If you've genuinely corrupted state (dropped tables you shouldn't have,
|
||||
applied a destructive migration in error):
|
||||
|
||||
```bash
|
||||
# See current goose state
|
||||
make migrate-status
|
||||
psql "$DATABASE_URL" -c \
|
||||
"SELECT version_id, is_applied, tstamp FROM goose_db_version ORDER BY id DESC LIMIT 10;"
|
||||
|
||||
# To force the version table back to a known-good number after
|
||||
# manually fixing the schema:
|
||||
psql "$DATABASE_URL" -c \
|
||||
"INSERT INTO goose_db_version (version_id, is_applied, tstamp) VALUES (<N>, true, NOW());"
|
||||
```
|
||||
|
||||
## 28. Bootstrap goose on a fresh clone of the schema
|
||||
|
||||
If you create a new Neon branch / dev DB and need to bring it under
|
||||
goose management:
|
||||
|
||||
```bash
|
||||
export DATABASE_URL="...<the new DB>..."
|
||||
|
||||
# Option A: fresh DB, no schema → just run up
|
||||
make migrate-up
|
||||
|
||||
# Option B: schema already populated (e.g., restored from a dump) →
|
||||
# mark v1 as already-applied
|
||||
goose -dir migrations postgres "$DATABASE_URL" version # creates table
|
||||
psql "$DATABASE_URL" -c \
|
||||
"INSERT INTO goose_db_version (version_id, is_applied, tstamp) VALUES (1, true, NOW());"
|
||||
```
|
||||
|
||||
This is also what was done for the live prod DB at goose-adoption time
|
||||
(commit `12b2f9d`).
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user