mirror of
https://github.com/stack-auth/stack.git
synced 2026-07-20 21:29:36 +08:00
revert(db): keep bulldozer timefold pg_cron worker for rollback
Reverts unscheduling/dropping the pg_cron job and its worker function so the SQL bulldozer path stays intact and revertible.
This commit is contained in:
-37
@@ -1,37 +0,0 @@
|
||||
-- Retire the SQL bulldozer timefold worker.
|
||||
--
|
||||
-- The live payments path now runs on bulldozer-js (an in-process 1-second tick
|
||||
-- loop drives timefolds), so the Postgres pg_cron job and its worker function
|
||||
-- are dead code. We unschedule the cron job and drop the function in a single
|
||||
-- transaction so there is never a window where the scheduled job exists but the
|
||||
-- function it calls does not.
|
||||
--
|
||||
-- We only swallow the two benign "pg_cron isn't really here" cases: the cron
|
||||
-- extension being absent entirely, and the cron.job table being missing. We do
|
||||
-- NOT swallow unschedule failures such as insufficient_privilege — if pg_cron is
|
||||
-- present and we cannot prove the job is gone, we must abort (rolling back the
|
||||
-- DROP FUNCTION below) rather than leave a scheduled job calling a function we
|
||||
-- just deleted, which would error every second. A human must then resolve the
|
||||
-- privilege issue and re-run. The backing tables are dropped in the following
|
||||
-- migration, after this commit guarantees nothing calls the function anymore.
|
||||
-- SPLIT_STATEMENT_SENTINEL
|
||||
-- SINGLE_STATEMENT_SENTINEL
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regnamespace('cron') IS NULL THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
BEGIN
|
||||
PERFORM cron.unschedule("jobid")
|
||||
FROM cron.job
|
||||
WHERE "jobname" = 'bulldozer-timefold-worker';
|
||||
EXCEPTION
|
||||
WHEN undefined_table THEN
|
||||
NULL;
|
||||
END;
|
||||
END
|
||||
$$;
|
||||
-- SPLIT_STATEMENT_SENTINEL
|
||||
-- SINGLE_STATEMENT_SENTINEL
|
||||
DROP FUNCTION IF EXISTS public.bulldozer_timefold_process_queue();
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import type { Sql } from "postgres";
|
||||
import { expect } from "vitest";
|
||||
|
||||
const functionExists = async (sql: Sql): Promise<boolean> => {
|
||||
const rows = await sql`
|
||||
SELECT 1
|
||||
FROM pg_proc p
|
||||
JOIN pg_namespace n ON n.oid = p.pronamespace
|
||||
WHERE n.nspname = 'public'
|
||||
AND p.proname = 'bulldozer_timefold_process_queue'
|
||||
`;
|
||||
return rows.length > 0;
|
||||
};
|
||||
|
||||
const cronPresent = async (sql: Sql): Promise<boolean> => {
|
||||
const rows = await sql`SELECT to_regnamespace('cron') IS NOT NULL AS present`;
|
||||
return Boolean(rows[0].present);
|
||||
};
|
||||
|
||||
export const preMigration = async (sql: Sql) => {
|
||||
// Sanity: the worker function must exist before this migration runs, otherwise
|
||||
// the test isn't actually exercising the drop.
|
||||
expect(await functionExists(sql)).toBe(true);
|
||||
};
|
||||
|
||||
export const postMigration = async (sql: Sql) => {
|
||||
// The worker function is gone.
|
||||
expect(await functionExists(sql)).toBe(false);
|
||||
|
||||
// If pg_cron is installed (it is in dev/CI Postgres), the worker job is gone
|
||||
// too. Guarded so the test still passes on a Postgres without pg_cron,
|
||||
// mirroring the best-effort guard in the migration itself.
|
||||
if (await cronPresent(sql)) {
|
||||
const jobs = await sql`
|
||||
SELECT 1 FROM cron.job WHERE "jobname" = 'bulldozer-timefold-worker'
|
||||
`;
|
||||
expect(jobs).toHaveLength(0);
|
||||
}
|
||||
|
||||
// Idempotency: re-running the teardown statements must be a no-op (the
|
||||
// migration uses DROP ... IF EXISTS and a guarded unschedule), not an error.
|
||||
await sql`DROP FUNCTION IF EXISTS public.bulldozer_timefold_process_queue()`;
|
||||
if (await cronPresent(sql)) {
|
||||
await sql`SELECT cron.unschedule("jobid") FROM cron.job WHERE "jobname" = 'bulldozer-timefold-worker'`;
|
||||
}
|
||||
expect(await functionExists(sql)).toBe(false);
|
||||
};
|
||||
Reference in New Issue
Block a user