From a56ef5408093e4fa2627baa7b87796479334a55d Mon Sep 17 00:00:00 2001 From: Peter Wielander Date: Tue, 19 May 2026 21:24:39 +0700 Subject: [PATCH 1/2] fix(world-postgres): bootstrap graphile-worker schema in setup CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `workflow-postgres-setup` now installs the `graphile_worker` schema in addition to the drizzle migrations so that by the time any consumer calls `world.start()`, both schemas already exist. This eliminates the inter-process race on graphile-worker's `installSchema` where concurrent `CREATE SCHEMA IF NOT EXISTS` calls could both pass the MVCC-snapshotted existence check and one would fail with `duplicate key value violates unique constraint "pg_namespace_nspname_index"`. Reproduced locally against a fresh postgres:18-alpine with 8 parallel `makeWorkerUtils().migrate()` calls — 7/8 fail without the pre-bootstrap, 0/8 fail after running `workflow-postgres-setup` first. Co-Authored-By: Claude Opus 4.7 (1M context) --- .changeset/setup-graphile-worker-schema.md | 5 +++++ packages/world-postgres/src/cli.ts | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 .changeset/setup-graphile-worker-schema.md diff --git a/.changeset/setup-graphile-worker-schema.md b/.changeset/setup-graphile-worker-schema.md new file mode 100644 index 0000000000..298e4d7c60 --- /dev/null +++ b/.changeset/setup-graphile-worker-schema.md @@ -0,0 +1,5 @@ +--- +"@workflow/world-postgres": patch +--- + +`workflow-postgres-setup` now also bootstraps the `graphile_worker` schema, so concurrent `world.start()` callers (e.g. dev server + test runner on a fresh DB) don't race on the not-race-safe `CREATE SCHEMA IF NOT EXISTS` and fail with `duplicate key value violates unique constraint "pg_namespace_nspname_index"`. diff --git a/packages/world-postgres/src/cli.ts b/packages/world-postgres/src/cli.ts index c481a00333..1b022eaa38 100644 --- a/packages/world-postgres/src/cli.ts +++ b/packages/world-postgres/src/cli.ts @@ -3,6 +3,7 @@ import { fileURLToPath } from 'node:url'; import { config } from 'dotenv'; import { drizzle } from 'drizzle-orm/node-postgres'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; +import { makeWorkerUtils } from 'graphile-worker'; import { Pool } from 'pg'; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -44,6 +45,23 @@ async function setupDatabase() { migrationsSchema: 'workflow_drizzle', }); + // Also bootstrap the graphile-worker schema. Without this, the first + // process to call `world.start()` against a fresh DB is responsible + // for running graphile-worker's `installSchema`, and concurrent + // callers (e.g. the dev server + the test runner) can race on the + // not-race-safe `CREATE SCHEMA IF NOT EXISTS` and fail with + // `duplicate key value violates unique constraint + // "pg_namespace_nspname_index"`. Running it here, single-process, + // before any consumer starts means later `installSchema` calls find + // the schema present and skip the racing DDL path entirely. + console.log('📂 Bootstrapping graphile-worker schema...'); + const workerUtils = await makeWorkerUtils({ pgPool: pool }); + try { + await workerUtils.migrate(); + } finally { + await workerUtils.release(); + } + console.log('✅ Database schema created successfully!'); await pool.end(); From f22f9349cd253ccddece5b66299c1ff9b6691eb9 Mon Sep 17 00:00:00 2001 From: Peter Wielander Date: Tue, 19 May 2026 21:27:53 +0700 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Peter Wielander Signed-off-by: Peter Wielander --- .changeset/setup-graphile-worker-schema.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/setup-graphile-worker-schema.md b/.changeset/setup-graphile-worker-schema.md index 298e4d7c60..44eeeec74e 100644 --- a/.changeset/setup-graphile-worker-schema.md +++ b/.changeset/setup-graphile-worker-schema.md @@ -2,4 +2,4 @@ "@workflow/world-postgres": patch --- -`workflow-postgres-setup` now also bootstraps the `graphile_worker` schema, so concurrent `world.start()` callers (e.g. dev server + test runner on a fresh DB) don't race on the not-race-safe `CREATE SCHEMA IF NOT EXISTS` and fail with `duplicate key value violates unique constraint "pg_namespace_nspname_index"`. +`workflow-postgres-setup` now also bootstraps the `graphile_worker` schema, fixing potential race on setup when starting the app and a test runner at the same time