From 876516510b04c2aac49e7f128c1c87b02441e556 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 25 Aug 2026 10:00:17 +0000 Subject: [PATCH] fix: dump the whole cluster in the postgres 18 upgrade recipe Windmill creates instance datatable, DuckLake and wm_fork_* databases in the same cluster as windmill, so a single-database pg_dump followed by removing the volume loses them silently. Dump the cluster with pg_dumpall instead, which also carries the roles the RLS policies are granted to, with their passwords. Also wait on the healthcheck before restoring, stop services generically rather than by name, and ANALYZE after the restore. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Ha6ovKdT9XRoj5FyVe7fEt --- docker-compose.yml | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 48a55e8c3d..63e05d1c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,25 +14,28 @@ services: ## is supported upstream until Nov 2028, so staying on `image: postgres:16` with ## the old `db_data:/var/lib/postgresql/data` mount remains a valid option. ## - ## To move the data across, dump first while the old 16 container is still the - ## one running (git checkout the previous docker-compose.yml if you already - ## replaced it), with only db up: - ## docker compose stop windmill_server windmill_worker windmill_worker_native - ## docker compose exec -T db pg_dumpall -U postgres --globals-only --no-role-passwords > globals.sql - ## docker compose exec -T db pg_dump -U postgres -Fc windmill > windmill.dump - ## Check both files, then switch to this file and start 18 on an empty volume: + ## Migrating means moving the WHOLE CLUSTER, not the windmill database. Windmill + ## creates instance datatable, DuckLake and wm_fork_* databases alongside it, and + ## grants its row-level security policies to cluster-level roles; a single-database + ## pg_dump carries neither, and the volume is gone before anyone notices. Dump + ## while the 16 container is still the one running (git checkout the previous + ## docker-compose.yml if you already replaced it): + ## docker compose down && docker compose up --wait db + ## docker compose exec -T db pg_dumpall -U postgres > cluster.sql + ## Check cluster.sql lists every database, then switch to this file: ## docker compose down ## docker volume ls | grep db_data # then remove the one this project owns ## docker volume rm - ## docker compose up -d db - ## docker compose exec -T db psql -U postgres -d postgres < globals.sql - ## docker compose exec -T db pg_restore -U postgres -d windmill --no-owner --exit-on-error < windmill.dump + ## 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 up -d - ## Loading globals.sql is not optional. Windmill grants its row-level security - ## policies to the cluster-level windmill_admin and windmill_user roles, which a - ## database-only dump does not carry, and pg_restore silently drops every policy - ## whose grantee role is missing. The one error to expect is psql reporting - ## `role "postgres" already exists`, which the fresh cluster bootstraps itself. + ## `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. db: deploy: # To use an external database, set replicas to 0 and set DATABASE_URL to the external database url in the .env file