Initial commit: Kalendartool (Next.js, Prisma, Docker)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
43
lib/db/tx.ts
Normal file
43
lib/db/tx.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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 mit Invite-Verbrauch, 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user