From 78ab7859ee897d746261c46628aa72b78ea73631 Mon Sep 17 00:00:00 2001 From: nomsoscript Date: Thu, 30 Jul 2026 01:12:08 +0100 Subject: [PATCH] fix: use shared webhook retry delay helper (#597) --- src/modules/webhooks/webhook.service.test.ts | 15 ++++++++++++--- src/modules/webhooks/webhook.service.ts | 8 +++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/modules/webhooks/webhook.service.test.ts b/src/modules/webhooks/webhook.service.test.ts index 116c0ae..c9374cf 100644 --- a/src/modules/webhooks/webhook.service.test.ts +++ b/src/modules/webhooks/webhook.service.test.ts @@ -137,6 +137,7 @@ describe('dispatchWebhookEvent', () => { beforeEach(() => { jest.useFakeTimers(); global.fetch = jest.fn(); + jest.spyOn(Math, 'random').mockReturnValue(0); }); afterEach(() => { @@ -313,7 +314,14 @@ describe('dispatchWebhookEvent', () => { }), 'Webhook delivery failed, retrying' ); - expect(logger.error).toHaveBeenCalledWith( + const exhaustionLogCalls = (logger.error as jest.Mock).mock.calls.filter( + ([, message]) => + message === 'Webhook delivery exhausted all retries, flagged as failing' + ); + expect(exhaustionLogCalls).toHaveLength(1); + + const [exhaustionLogFields] = exhaustionLogCalls[0]; + expect(exhaustionLogFields).toEqual( expect.objectContaining({ webhook_id: 'wh-1', creator_id: 'creator-1', @@ -321,9 +329,10 @@ describe('dispatchWebhookEvent', () => { total_attempts: envConfig.WEBHOOK_RETRY_MAX_ATTEMPTS, last_error_code: 'Network error', flagged_at: expect.any(String), - }), - 'Webhook delivery exhausted all retries, flagged as failing' + }) ); + expect(exhaustionLogFields.callback_url).toBeUndefined(); + expect(exhaustionLogFields.callbackUrl).toBeUndefined(); // Verify attempt log was emitted for every retry attempt (success: false, response_status: null) for (let attempt = 1; attempt <= envConfig.WEBHOOK_RETRY_MAX_ATTEMPTS; attempt++) { diff --git a/src/modules/webhooks/webhook.service.ts b/src/modules/webhooks/webhook.service.ts index 22fa12a..cc051c2 100644 --- a/src/modules/webhooks/webhook.service.ts +++ b/src/modules/webhooks/webhook.service.ts @@ -2,6 +2,7 @@ import { prisma } from '../../utils/prisma.utils'; import { logger } from '../../utils/logger.utils'; import { envConfig } from '../../config'; import { maskWebhookUrl } from '../../utils/webhook-mask.utils'; +import { computeRetryDelay } from '../../utils/retry-delay.utils'; import { buildWebhookPayload } from './webhook-payload.utils'; import type { CreateWebhookInput, @@ -193,6 +194,7 @@ async function attemptDelivery( attempt = 1 ): Promise { const maxAttempts = envConfig.WEBHOOK_RETRY_MAX_ATTEMPTS; + const maxDelayMs = 30_000; const startTime = Date.now(); let responseStatus: number | null = null; let responseTimeMs = 0; @@ -282,7 +284,11 @@ async function attemptDelivery( }); if (attempt < maxAttempts) { - const delay = Math.pow(2, attempt) * 1000; + const delay = computeRetryDelay( + attempt, + envConfig.WEBHOOK_RETRY_BASE_DELAY_MS, + maxDelayMs + ); logger.warn( { webhook_id: webhookId,