From a6938126c76db92fd25591197bfad27602010e72 Mon Sep 17 00:00:00 2001 From: Eiman Date: Fri, 23 Jan 2026 10:24:01 -0600 Subject: [PATCH] fix: retry webhooks on 429 and 403 responses Previously, only 5xx errors triggered webhook retries. This change adds 429 (Too Many Requests) and 403 (Forbidden) to the retry logic, treating them the same as server errors with exponential backoff. This prevents webhook events from being lost when the destination endpoint rate-limits requests or returns transient auth errors. Also fixes a pre-existing lint error (unused template literal). Co-Authored-By: Claude Opus 4.5 --- src/worker/tasks/send-webhook-worker.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/worker/tasks/send-webhook-worker.ts b/src/worker/tasks/send-webhook-worker.ts index ef1eaee3..651b15d1 100644 --- a/src/worker/tasks/send-webhook-worker.ts +++ b/src/worker/tasks/send-webhook-worker.ts @@ -85,7 +85,7 @@ const handler: Processor = async (job: Job) => { logger({ service: "worker", level: "warn", - message: `[Webhook] Transaction not found for webhook`, + message: "[Webhook] Transaction not found for webhook", queueId: data.queueId, data: { eventType: data.type, @@ -137,15 +137,21 @@ const handler: Processor = async (job: Job) => { }); } - // Throw on 5xx so it remains in the queue to retry later. - if (resp && resp.status >= 500) { + // Throw on 5xx, 429 (rate limit), or 403 (forbidden) so it remains in the queue to retry later. + if (resp && (resp.status >= 500 || resp.status === 429 || resp.status === 403)) { + const errorType = + resp.status === 429 + ? "rate limited" + : resp.status === 403 + ? "forbidden" + : "server error"; const error = new Error( `Received status ${resp.status} from webhook ${webhook.url}.`, ); job.log(error.message); logger({ level: "error", - message: `[Webhook] 5xx error, will retry`, + message: `[Webhook] ${resp.status} ${errorType}, will retry`, service: "worker", queueId: transactionId, data: {