Files
plp/apps/api/src/safety/safety-lock.service.ts
T

29 lines
972 B
TypeScript

import { Injectable } from "@nestjs/common";
import { type Prisma } from "@prisma/client";
/**
* Transaction-scoped serialization protocol for policy subjects.
*
* Every transaction that reads or writes block, sanction, or account-status
* policy MUST call this method first for every affected account. IDs are
* de-duplicated and sorted so overlapping multi-account operations cannot
* deadlock. The lock is released by PostgreSQL only when the transaction ends;
* callers must therefore pass the transaction client, never PrismaService.
*/
@Injectable()
export class SafetyLockService {
async lockAccounts(
tx: Prisma.TransactionClient,
accountIds: readonly string[],
): Promise<void> {
const canonicalIds = Array.from(new Set(accountIds)).sort();
for (const accountId of canonicalIds) {
await tx.$executeRaw`
SELECT pg_advisory_xact_lock(
hashtextextended(${`safety:${accountId}`}, 0)
)
`;
}
}
}