perf: remove paid result account lock contention

This commit is contained in:
hectorzhao
2026-08-21 10:40:28 +08:00
parent 487b5282a6
commit fcf6d3e6b4
6 changed files with 58 additions and 48 deletions
+10 -8
View File
@@ -11,7 +11,7 @@ function createPrismaMock() {
findMany: jest.fn().mockResolvedValue([]),
},
tenantAccount: {
findMany: jest.fn(),
findMany: jest.fn().mockResolvedValue([]),
findUnique: jest.fn().mockImplementation(() => Promise.resolve({ ...accountState })),
findUniqueOrThrow: jest.fn().mockImplementation(() => Promise.resolve({ ...accountState })),
create: jest.fn(),
@@ -30,7 +30,7 @@ function createPrismaMock() {
}),
},
accountTransaction: {
findMany: jest.fn(),
findMany: jest.fn().mockResolvedValue([]),
findFirst: jest.fn(),
findUnique: jest.fn().mockResolvedValue(null),
findUniqueOrThrow: jest.fn().mockImplementation(({ where }) => Promise.resolve({ id: 'tx-charged', idempotencyKey: where.idempotencyKey })),
@@ -55,6 +55,7 @@ function createPrismaMock() {
create: jest.fn().mockResolvedValue({ id: 'operation-1' }),
},
$executeRaw: jest.fn(),
$queryRaw: jest.fn(),
};
return Object.assign(prisma, {
$transaction: jest.fn((callback: (client: typeof prisma) => unknown) => callback(prisma)),
@@ -319,11 +320,11 @@ describe('BillingService', () => {
it('settles a frozen SMS charge with one account lock and an idempotent ledger pair', async () => {
const prisma = createPrismaMock();
const rows = new Map<string, Record<string, unknown>>();
prisma.accountTransaction.findUnique.mockImplementation(({ where }) => Promise.resolve(rows.get(where.idempotencyKey) ?? null));
prisma.accountTransaction.findUniqueOrThrow.mockImplementation(({ where }) => Promise.resolve(rows.get(where.idempotencyKey)));
prisma.accountTransaction.createMany.mockImplementation(({ data }) => {
data.forEach((row: Record<string, unknown>) => rows.set(String(row.idempotencyKey), { id: `tx-${row.transactionType}`, ...row }));
return Promise.resolve({ count: data.length });
prisma.accountTransaction.findMany.mockImplementation(() => Promise.resolve([...rows.values()]));
prisma.$queryRaw.mockImplementation(() => {
const charged = { id: 'tx-charged', idempotencyKey: 'sms-charge:msg-paid-1', transactionType: 'charged', amountCents: -325 };
rows.set(String(charged.idempotencyKey), charged);
return Promise.resolve([charged]);
});
const service = new BillingService(prisma as never);
const input = { tenantId: 'tenant-1', amountCents: 325, messageId: 'msg-paid-1', taskId: 'task-paid-1' };
@@ -333,7 +334,8 @@ describe('BillingService', () => {
expect(first).toEqual(expect.objectContaining({ transactionType: 'charged', amountCents: -325 }));
expect(replay).toEqual(first);
expect(prisma.accountTransaction.createMany).toHaveBeenCalledTimes(1);
expect(prisma.$queryRaw).toHaveBeenCalledTimes(1);
expect(prisma.$executeRaw).not.toHaveBeenCalled();
expect(prisma.tenantAccount.update).not.toHaveBeenCalled();
});