Transaktionen: Wartezeit 10 s und Zeitlimit 20 s statt Prisma-Standard

Unter paralleler Last scheiterten Tests sporadisch mit „Unable to start a transaction in the given time“.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 19:14:31 +02:00
co-authored by Claude Opus 5
parent 969bc4e12c
commit c3712598c1
+9 -3
View File
@@ -406,7 +406,7 @@ export function dbForTenant(tenantId: string) {
args, args,
(a) => delegate[operation](a), (a) => delegate[operation](a),
); );
}); }, TX_DEFAULTS);
}, },
}, },
}, },
@@ -415,6 +415,12 @@ export function dbForTenant(tenantId: string) {
export type TenantDb = ReturnType<typeof dbForTenant>; export type TenantDb = ReturnType<typeof dbForTenant>;
/**
* Interactive transaction limits. Prisma defaults (maxWait 2 s, timeout 5 s) fail under parallel load
* (pool exhausted while notifications/mails run inside a transaction) → wider but still bounded.
*/
const TX_DEFAULTS = { maxWait: 10_000, timeout: 20_000 } as const;
/** /**
* Run `fn` atomically for one tenant. ALWAYS use this (or `inTransaction` in services) * Run `fn` atomically for one tenant. ALWAYS use this (or `inTransaction` in services)
* instead of `db.$transaction(...)` for multi-step writes — atomic in both modes: * instead of `db.$transaction(...)` for multi-step writes — atomic in both modes:
@@ -431,7 +437,7 @@ export async function tenantTransaction<T>(
): Promise<T> { ): Promise<T> {
if (!RLS_ENFORCED) { if (!RLS_ENFORCED) {
if (isTransactionClient(db)) return fn(db); if (isTransactionClient(db)) return fn(db);
return db.$transaction((tx) => fn(tx as unknown as TenantDb), options) as Promise<T>; return db.$transaction((tx) => fn(tx as unknown as TenantDb), { ...TX_DEFAULTS, ...options }) as Promise<T>;
} }
const active = tenantTx.getStore(); const active = tenantTx.getStore();
if (active) { if (active) {
@@ -441,7 +447,7 @@ export async function tenantTransaction<T>(
return appBase!.$transaction(async (tx) => { return appBase!.$transaction(async (tx) => {
await tx.$executeRaw`SELECT set_config('app.tenant_id', ${tenantId}, true)`; await tx.$executeRaw`SELECT set_config('app.tenant_id', ${tenantId}, true)`;
return tenantTx.run({ tenantId, tx }, () => fn(db)); return tenantTx.run({ tenantId, tx }, () => fn(db));
}, options); }, { ...TX_DEFAULTS, ...options });
} }
/** Interactive transaction clients have no $transaction method. */ /** Interactive transaction clients have no $transaction method. */