feat: harden sessions and track downstream acknowledgements
This commit is contained in:
@@ -213,6 +213,7 @@ function createPrismaMock() {
|
||||
}),
|
||||
findMany: jest.fn().mockResolvedValue([]),
|
||||
update: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'delivery-1', tenantId: 'tenant-1', applicationId: 'app-1', messageId: 'MSG-1', deliveryType: 'receipt', ...data })),
|
||||
updateMany: jest.fn().mockResolvedValue({ count: 1 }),
|
||||
},
|
||||
gatewaySubmitDeadLetter: {
|
||||
upsert: jest.fn().mockResolvedValue({ id: 'dead-1' }),
|
||||
@@ -1454,6 +1455,49 @@ describe('SendChainService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('only marks downstream delivery delivered after a successful CMPP_DELIVER_RESP', async () => {
|
||||
const { service, prisma } = createService();
|
||||
|
||||
await service.markDownstreamDeliverySent({
|
||||
id: 'delivery-1',
|
||||
connectionId: 'conn-1',
|
||||
sequenceId: '37',
|
||||
messageId: '9016479179509871733',
|
||||
sentAt: '2026-07-14T03:40:18.030Z',
|
||||
ackDeadlineAt: '2026-07-14T03:40:48.030Z',
|
||||
});
|
||||
expect(prisma.cmppDownstreamDelivery.updateMany).toHaveBeenLastCalledWith(expect.objectContaining({
|
||||
where: { id: 'delivery-1', status: { not: 'delivered' } },
|
||||
data: expect.objectContaining({ status: 'awaiting_ack', ackSequenceId: '37', connectionId: 'conn-1' }),
|
||||
}));
|
||||
|
||||
await service.acknowledgeDownstreamDelivery({
|
||||
id: 'delivery-1',
|
||||
connectionId: 'conn-1',
|
||||
sequenceId: '37',
|
||||
messageId: '9016479179509871733',
|
||||
result: 0,
|
||||
acknowledgedAt: '2026-07-14T03:40:18.060Z',
|
||||
});
|
||||
expect(prisma.cmppDownstreamDelivery.updateMany).toHaveBeenLastCalledWith(expect.objectContaining({
|
||||
data: expect.objectContaining({ status: 'delivered', ackResult: 0, deliveredAt: new Date('2026-07-14T03:40:18.060Z') }),
|
||||
}));
|
||||
});
|
||||
|
||||
it('does not automatically retry an unacknowledged delivery when its policy snapshot is disabled', async () => {
|
||||
const { service, prisma } = createService();
|
||||
prisma.cmppDownstreamDelivery.findUnique.mockResolvedValue({
|
||||
id: 'delivery-1', tenantId: 'tenant-1', applicationId: 'app-1', messageId: 'MSG-1',
|
||||
deliveryType: 'receipt', status: 'awaiting_ack', retryEnabled: false, retryCount: 0,
|
||||
});
|
||||
|
||||
await service.markDownstreamDeliveryFailed('delivery-1', 'CMPP_DELIVER_RESP timeout', 'ack_timeout');
|
||||
|
||||
expect(prisma.cmppDownstreamDelivery.update).toHaveBeenCalledWith(expect.objectContaining({
|
||||
data: expect.objectContaining({ status: 'unconfirmed', retryCount: 1, nextRetryAt: null }),
|
||||
}));
|
||||
});
|
||||
|
||||
it('uses exponential backoff for downstream delivery retries before final failure', async () => {
|
||||
const { service, prisma } = createService();
|
||||
const previousBase = process.env.CMPP_DOWNSTREAM_RETRY_DELAY_MS;
|
||||
|
||||
Reference in New Issue
Block a user