fix: analyze every restored database and check the restore for errors

ANALYZE is per-database, so the sibling datatable/DuckLake/wm_fork_* databases the
recipe now restores were left with no planner statistics; vacuumdb --all covers
them. psql does not stop on error and the old volume is gone by that point, so
the restore needs an explicit grep rather than a trusted exit code.

Also note that logical replication slots are never dumped, so a Postgres trigger
reading a database in this cluster comes back disabled until it is re-saved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6ovKdT9XRoj5FyVe7fEt
This commit is contained in:
Ruben Fiszel
2026-08-25 10:19:48 +00:00
co-authored by Claude Opus 5
parent 876516510b
commit cc88fd8aac
+12 -8
View File
@@ -27,15 +27,19 @@ services:
## docker volume ls | grep db_data # then remove the one this project owns
## docker volume rm <that_volume>
## docker compose up --wait db
## docker compose exec -T db psql -U postgres -d postgres < cluster.sql
## docker compose exec -T db psql -U postgres -d windmill -c ANALYZE
## docker compose exec -T db psql -U postgres -d postgres < cluster.sql > restore.log 2>&1
## grep -i '^ERROR' restore.log # only the two expected ones, see below
## docker compose exec -T db vacuumdb -U postgres --all --analyze-in-stages
## docker compose up -d
## `database "windmill" already exists` and `role "postgres" already exists` are
## expected; the fresh cluster bootstraps both, and psql carries on to load into
## them. ANALYZE is not optional: a restored cluster starts with no planner
## statistics, which reads as "the upgrade made Windmill slow" until autovacuum
## catches up. `up --wait` rather than `up -d` because psql would otherwise race
## initdb on a fresh volume.
## `up --wait` because psql would otherwise race initdb on a fresh volume. psql
## does not stop on error and the old volume is already gone by then, so grep the
## log rather than trust its exit code; `database "windmill" already exists` and
## `role "postgres" already exists` are the two the fresh cluster causes itself.
## vacuumdb spans every restored database, which a plain ANALYZE would not: each
## comes back with no planner statistics, and a fork database is where the stall
## shows. Postgres triggers reading a database in this cluster come back disabled
## with "replication slot ... no longer exists", since slots are never dumped;
## re-saving the trigger recreates the slot.
db:
deploy:
# To use an external database, set replicas to 0 and set DATABASE_URL to the external database url in the .env file