From 161acff754bda89bd1bbddb76b1f6d4fd5cc92ab Mon Sep 17 00:00:00 2001 From: Rhys Cox Date: Fri, 1 May 2026 14:43:04 +0100 Subject: [PATCH] CCM-16073 - Attempt at fixing runaway lambdas --- .../src/__tests__/handler.test.ts | 6 ++---- lambdas/https-client-lambda/src/handler.ts | 12 +++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lambdas/https-client-lambda/src/__tests__/handler.test.ts b/lambdas/https-client-lambda/src/__tests__/handler.test.ts index 0f4581aa..5d6fc5a1 100644 --- a/lambdas/https-client-lambda/src/__tests__/handler.test.ts +++ b/lambdas/https-client-lambda/src/__tests__/handler.test.ts @@ -373,8 +373,7 @@ describe("processRecords", () => { expect(failures).toEqual([{ itemIdentifier: "msg-1" }]); const visibilityDelay = mockChangeVisibility.mock.calls[0]![1] as number; - expect(visibilityDelay).toBeGreaterThanOrEqual(2); - expect(visibilityDelay).toBeLessThanOrEqual(6); + expect(visibilityDelay).toBe(2); expect(mockSendToDlq).not.toHaveBeenCalled(); expect(mockDeliverPayload).not.toHaveBeenCalled(); }); @@ -391,8 +390,7 @@ describe("processRecords", () => { expect(failures).toEqual([{ itemIdentifier: "msg-1" }]); const visibilityDelay = mockChangeVisibility.mock.calls[0]![1] as number; - expect(visibilityDelay).toBeGreaterThanOrEqual(30); - expect(visibilityDelay).toBeLessThanOrEqual(34); + expect(visibilityDelay).toBe(30); expect(mockSendToDlq).not.toHaveBeenCalled(); expect(mockDeliverPayload).not.toHaveBeenCalled(); }); diff --git a/lambdas/https-client-lambda/src/handler.ts b/lambdas/https-client-lambda/src/handler.ts index 586c811c..93eea777 100644 --- a/lambdas/https-client-lambda/src/handler.ts +++ b/lambdas/https-client-lambda/src/handler.ts @@ -216,14 +216,14 @@ async function handleBatchDenied( reason: string, retryAfterMs: number, ): Promise { - const delaySec = Math.ceil(retryAfterMs / 1000); + const baseDelaySec = Math.max(1, Math.ceil(retryAfterMs / 1000)); const correlationIds = batch.messages.map((m) => extractCorrelationId(m)); recordAdmissionDenied(clientId, batch.targetId, reason, correlationIds); const failures: SQSBatchItemFailure[] = []; for (const record of batch.records) { - // eslint-disable-next-line sonarjs/pseudo-random -- jitter for backoff, not security-sensitive - const jitterSec = Math.floor(Math.random() * 5); - await changeVisibility(record.receiptHandle, delaySec + jitterSec); + const receiveCount = Number(record.attributes.ApproximateReceiveCount); + const delaySec = receiveCount * baseDelaySec; + await changeVisibility(record.receiptHandle, delaySec); failures.push({ itemIdentifier: record.messageId }); } return { failures, deliveredCount: 0, dlqCount: 0 }; @@ -362,7 +362,9 @@ async function processTargetBatch( rejectedCorrelationIds, ); for (const record of rejected) { - await changeVisibility(record.receiptHandle, 1); + const receiveCount = Number(record.attributes.ApproximateReceiveCount); + const delaySec = receiveCount * 1; + await changeVisibility(record.receiptHandle, delaySec); failures.push({ itemIdentifier: record.messageId }); } }