diff --git a/src/webhooks/webhook.dispatcher.ts b/src/webhooks/webhook.dispatcher.ts index 2c49833..83cb0cf 100644 --- a/src/webhooks/webhook.dispatcher.ts +++ b/src/webhooks/webhook.dispatcher.ts @@ -1,6 +1,6 @@ - import crypto from 'crypto'; -import { WebhookConfig, WebhookPayload } from './webhook.types.js'; +import { WebhookConfig, WebhookPayload, DeadLetterEntry, WebhookDeliveryStatus } from './webhook.types.js'; +import { WebhookStore } from './webhook.store.js'; import { logger } from '../logger.js'; const MAX_RETRIES = 5; @@ -12,6 +12,16 @@ function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } +// Calculate exponential backoff with jitter to avoid thundering herd +function calculateBackoff(attempt: number): number { + const exponentialDelay = BASE_DELAY_MS * Math.pow(2, attempt); + // Add jitter: random value between 0-25% of the exponential delay + const jitter = Math.random() * 0.25 * exponentialDelay; + const delayWithJitter = exponentialDelay + jitter; + // Cap at maximum delay + return Math.min(delayWithJitter, MAX_DELAY_MS); +} + function signPayload(secret: string, body: string): string { return crypto.createHmac('sha256', secret).update(body).digest('hex'); } diff --git a/src/webhooks/webhook.store.ts b/src/webhooks/webhook.store.ts index 5cbcde6..dc052cc 100644 --- a/src/webhooks/webhook.store.ts +++ b/src/webhooks/webhook.store.ts @@ -1,6 +1,7 @@ -import { WebhookConfig, WebhookEventType } from './webhook.types.js'; +import { WebhookConfig, WebhookEventType, DeadLetterEntry } from './webhook.types.js'; const store = new Map(); +const deadLetterStore = new Map(); export const WebhookStore = { register(config: WebhookConfig): void { @@ -27,4 +28,4 @@ export const WebhookStore = { clear(): void { store.clear(); }, -}; \ No newline at end of file +};