Diagnose tenant lock migration blockers

This commit is contained in:
2026-07-14 16:50:27 +02:00
parent 4c03a96cbe
commit d0f5a72350

View File

@@ -12,6 +12,65 @@ const logStep = (message: string) => {
console.log(`[tenant-lock-migration] ${message}`) console.log(`[tenant-lock-migration] ${message}`)
} }
const printRelationLocks = async (db: ReturnType<typeof drizzle>, relationName: string) => {
const result = await db.execute(sql`
SELECT
activity.pid,
activity.state,
activity.wait_event_type,
activity.wait_event,
now() - activity.query_start AS query_age,
locks.mode,
locks.granted,
left(activity.query, 500) AS query
FROM pg_locks locks
JOIN pg_class relation ON relation.oid = locks.relation
LEFT JOIN pg_stat_activity activity ON activity.pid = locks.pid
WHERE relation.relname = ${relationName}
ORDER BY locks.granted ASC, activity.query_start ASC NULLS LAST;
`)
if (!result.rows.length) {
logStep(`Keine aktiven Locks fuer ${relationName} gefunden`)
return
}
logStep(`Aktive Locks fuer ${relationName}:`)
for (const row of result.rows as Record<string, any>[]) {
console.log(JSON.stringify({
pid: row.pid,
state: row.state,
waitEventType: row.wait_event_type,
waitEvent: row.wait_event,
queryAge: row.query_age,
mode: row.mode,
granted: row.granted,
query: row.query,
}, null, 2))
}
}
const executeStep = async (
db: ReturnType<typeof drizzle>,
message: string,
statement: ReturnType<typeof sql>,
lockRelationName?: string,
) => {
logStep(message)
try {
await db.execute(statement)
} catch (err: any) {
const code = err?.cause?.code || err?.code
if (lockRelationName && ["55P03", "57014"].includes(code)) {
logStep(`Konnte Lock fuer ${lockRelationName} nicht rechtzeitig bekommen`)
await printRelationLocks(db, lockRelationName)
}
throw err
}
}
async function run() { async function run() {
let connectionString = process.env.DATABASE_URL let connectionString = process.env.DATABASE_URL
@@ -42,24 +101,22 @@ async function run() {
logStep("Teste DB-Verbindung") logStep("Teste DB-Verbindung")
await db.execute(sql`SELECT 1`) await db.execute(sql`SELECT 1`)
logStep("Setze Statement-Timeout") logStep("Setze Lock- und Statement-Timeout")
await db.execute(sql`SET statement_timeout = '30s'`) await db.execute(sql`SET lock_timeout = '10s'`)
await db.execute(sql`SET statement_timeout = '2min'`)
logStep("Erweitere tenant_export_jobs") await executeStep(db, "Erweitere tenant_export_jobs", sql`
await db.execute(sql`
ALTER TABLE "tenant_export_jobs" ALTER TABLE "tenant_export_jobs"
ADD COLUMN IF NOT EXISTS "operation" text DEFAULT 'export' NOT NULL, ADD COLUMN IF NOT EXISTS "operation" text DEFAULT 'export' NOT NULL,
ADD COLUMN IF NOT EXISTS "previous_tenant_locked" "locked_tenant"; ADD COLUMN IF NOT EXISTS "previous_tenant_locked" "locked_tenant";
`) `, "tenant_export_jobs")
logStep("Erweitere tenants") await executeStep(db, "Erweitere tenants", sql`
await db.execute(sql`
ALTER TABLE "tenants" ALTER TABLE "tenants"
ADD COLUMN IF NOT EXISTS "locked_by_export_job_id" uuid; ADD COLUMN IF NOT EXISTS "locked_by_export_job_id" uuid;
`) `, "tenants")
logStep("Prüfe Foreign Key") await executeStep(db, "Pruefe Foreign Key", sql`
await db.execute(sql`
DO $$ DO $$
BEGIN BEGIN
IF NOT EXISTS ( IF NOT EXISTS (
@@ -75,15 +132,13 @@ async function run() {
ON DELETE SET NULL; ON DELETE SET NULL;
END IF; END IF;
END $$; END $$;
`) `, "tenants")
logStep("Prüfe Drizzle-Schema") await executeStep(db, "Pruefe Drizzle-Schema", sql`
await db.execute(sql`
CREATE SCHEMA IF NOT EXISTS drizzle; CREATE SCHEMA IF NOT EXISTS drizzle;
`) `)
logStep("Prüfe Drizzle-Migrationstabelle") await executeStep(db, "Pruefe Drizzle-Migrationstabelle", sql`
await db.execute(sql`
CREATE TABLE IF NOT EXISTS drizzle.__drizzle_migrations ( CREATE TABLE IF NOT EXISTS drizzle.__drizzle_migrations (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
hash text NOT NULL, hash text NOT NULL,
@@ -91,8 +146,7 @@ async function run() {
); );
`) `)
logStep("Setze Drizzle-Journal auf 0055") await executeStep(db, "Setze Drizzle-Journal auf 0055", sql`
await db.execute(sql`
INSERT INTO drizzle.__drizzle_migrations (hash, created_at) INSERT INTO drizzle.__drizzle_migrations (hash, created_at)
SELECT 'manual-0055_tenant_export_maintenance_lock', 1784021669805 SELECT 'manual-0055_tenant_export_maintenance_lock', 1784021669805
WHERE NOT EXISTS ( WHERE NOT EXISTS (