Compare commits

...

2 Commits

Author SHA1 Message Date
Flea Flicker a91361296a fix(GRO-2672): correct reset.ts content (raw TS, not base64)
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Successful in 1m10s
2026-08-06 09:12:15 +00:00
Flea Flicker 48de6ec7c4 fix(GRO-2672): use drizzle-kit migrate in reset.ts to bypass HWM bug
CI / Lint & Typecheck (pull_request) Failing after 19s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Images (pull_request) Has been skipped
drizzle-orm's migrate() has a high-water-mark (HWM) bug: on a fresh DB,
migration 0000 sets the watermark to 2026-03-17. Migrations 0001, 0003,
0010, 0011 have stale 2025-era `when` timestamps and are silently
skipped. Migration 0003 (recurring_series) is critical -- its skip
leaves `recurring_series`, `appointments.series_id`, and
`appointments.series_index` missing. A downstream migration inside
migrate()'s single Postgres transaction then fails, rolling back
everything including 0000's `staff` and `services` tables.

Replace the drizzle-orm migrate() call with `pnpm exec drizzle-kit
migrate` (hash-based). drizzle-kit applies every unhashed migration
regardless of `when` ordering, matching the K8s migrate Job exactly.
2026-08-06 09:06:30 +00:00
+11 -4
View File
@@ -32,7 +32,7 @@
*/ */
import postgres from "postgres"; import postgres from "postgres";
import { drizzle } from "drizzle-orm/postgres-js"; import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator"; import { execSync } from "node:child_process";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path"; import { dirname, resolve } from "node:path";
import * as schema from "./schema.js"; import * as schema from "./schema.js";
@@ -46,7 +46,6 @@ import {
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
const MIGRATIONS_FOLDER = resolve(__dirname, "../migrations");
async function reset() { async function reset() {
const url = process.env.DATABASE_URL; const url = process.env.DATABASE_URL;
@@ -73,7 +72,7 @@ async function reset() {
// across processes regardless of how many connections the work uses — // across processes regardless of how many connections the work uses —
// it does NOT require the work to share the lock's session. // it does NOT require the work to share the lock's session.
// //
// Therefore `max` must be 2: 1 reserved for the lock + 1 free for // Therefore `max` must be >= 2: 1 reserved for the lock + >=1 free for
// the work. `max: 1` would let `reserve()` consume the only connection // the work. `max: 1` would let `reserve()` consume the only connection
// and every query inside the callback would block forever waiting for // and every query inside the callback would block forever waiting for
// a connection that never frees (connection-starvation deadlock). We // a connection that never frees (connection-starvation deadlock). We
@@ -122,7 +121,15 @@ async function reset() {
console.log("✓ All tables and enums dropped\n"); console.log("✓ All tables and enums dropped\n");
console.log("Running migrations..."); console.log("Running migrations...");
await migrate(db, { migrationsFolder: MIGRATIONS_FOLDER }); // GRO-2672: drizzle-orm's migrate() has a high-water-mark bug that skips
// migrations with stale `when` timestamps (0001, 0003, 0010, 0011). Use
// drizzle-kit instead -- it applies migrations by hash, matching the K8s
// migrate Job behaviour exactly.
execSync("pnpm exec drizzle-kit migrate", {
stdio: "inherit",
env: { ...process.env },
cwd: resolve(__dirname, ".."),
});
console.log("✓ Migrations applied\n"); console.log("✓ Migrations applied\n");
console.log("Seeding database..."); console.log("Seeding database...");