Files
kalendartool/lib/db/tx.ts

44 lines
1.4 KiB
TypeScript

/**
* Transaktions-Helper: SERIALIZABLE mit Retry bei Serialisierungs-
* konflikten (Prisma-Fehlercode P2034).
*
* Postgres bricht bei Parallelitaets-Anomalien unter SERIALIZABLE eine
* der beteiligten Transaktionen ab. Wiederholbare Operationen (z. B.
* Registrierung und Rollen-Aenderung) werden dann
* einfach erneut ausgefuehrt - der Konflikt loest sich auf, weil die
* andere Transaktion inzwischen committet hat.
*/
import { Prisma } from '@prisma/client';
import { prisma } from '@/lib/db/client';
/** Ist es ein wiederholbarer Serialisierungs-Konflikt? */
function isSerializationError(error: unknown): boolean {
return (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.code === 'P2034'
);
}
/**
* Fuehrt die Operation in einer SERIALIZABLE-Transaktion aus und
* wiederholt sie bei Serialisierungs-Konflikten (max. 3 Nachlaeufe).
*/
export async function withSerializableTx<T>(
operation: (tx: Prisma.TransactionClient) => Promise<T>,
maxRetries = 3,
): Promise<T> {
for (let attempt = 0; ; attempt++) {
try {
return await prisma.$transaction(operation, {
isolationLevel: 'Serializable',
});
} catch (error) {
if (attempt >= maxRetries || !isSerializationError(error)) {
throw error;
}
// Naechster Versuch: Die abgebrochene Transaktion hat nichts
// committet, ein erneuter Lauf sieht den aktuellen Stand.
}
}
}