Merge branch 'fix/v147-review-dbrole' into release/v1.47.0

This commit is contained in:
Marc-André Bombeck committed 2026-11-03 23:35:54 +01:00
commit 2d8b782f34
13 files changed
+1091 -337

No files matched your search

+13 -8
View File
@@ -89,20 +89,25 @@ function databaseOptions(
}
/**
* The worker's pg-boss. `createSchema` says whether pg-boss's first install
* may run `CREATE SCHEMA IF NOT EXISTS pgboss`. Postgres checks the database's
* CREATE privilege before it checks whether the schema exists, so under the
* app's restricted role (`scripts/db-app-role.mjs`), which may not create
* schemas, that statement fails even though the boot already created the
* schema for it. The caller passes false when the schema is there.
* The worker's pg-boss. `ownsQueueSchema` is false when the connection does
* not own the `pgboss` schema, which is how the app's restricted role
* (`scripts/db-app-role.mjs`) runs: the boot installed and migrated the
* schema as the owner, so pg-boss neither installs, migrates nor runs the
* index builds a migration queues (`migrate: false`), and never sends
* `CREATE SCHEMA IF NOT EXISTS` (`createSchema: false`), which Postgres
* refuses without the database's CREATE privilege even when the schema is
* there. With `migrate: false`, pg-boss refuses to start on a schema that is
* not at its version, rather than run on it.
*/
export function createWorkerBoss(
connectionString: string,
options: { createSchema?: boolean } = {},
options: { ownsQueueSchema?: boolean } = {},
): PgBoss {
return new PgBoss({
...databaseOptions(connectionString, "worker"),
...(options.createSchema === false ? { createSchema: false } : {}),
...(options.ownsQueueSchema === false
? { createSchema: false, migrate: false }
: {}),
});
}
+11 -7
View File
@@ -48,13 +48,17 @@ export async function startReminderWorker() {
return;
}
// The queue schema exists once a worker has started, and on every boot
// the restricted database role runs under (the entrypoint creates it for
// that role); only a fresh database without either needs pg-boss to
// create it.
const [{ present }] = await prisma.$queryRaw<{ present: boolean }[]>`
SELECT to_regnamespace('pgboss') IS NOT NULL AS present`;
const boss = createWorkerBoss(DATABASE_URL, { createSchema: !present });
// Under the restricted database role the boot installed and migrated the
// queue schema as its owner, and the role owns nothing there; pg-boss then
// only reads and writes rows. A connection that owns the schema, or a fresh
// database without one, lets pg-boss install and migrate it itself.
const [{ owned }] = await prisma.$queryRaw<{ owned: boolean | null }[]>`
SELECT pg_has_role(current_user, n.nspowner, 'USAGE') AS owned
FROM (SELECT 1) one
LEFT JOIN pg_namespace n ON n.nspname = 'pgboss'`;
const boss = createWorkerBoss(DATABASE_URL, {
ownsQueueSchema: owned !== false,
});
boss.on("error", (error: unknown) => {
workerLog("error", "boss emitted error", error);