29 lines
972 B
TypeScript
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)
|
|
)
|
|
`;
|
|
}
|
|
}
|
|
}
|