(webhookId: string, logger: Logger)
| 22 | |
| 23 | /** Increment the webhook's failure count. Auto-disables after MAX_CONSECUTIVE_FAILURES. */ |
| 24 | export async function markWebhookFailed(webhookId: string, logger: Logger): Promise<void> { |
| 25 | try { |
| 26 | const result = await db |
| 27 | .update(webhook) |
| 28 | .set({ |
| 29 | failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`, |
| 30 | lastFailedAt: new Date(), |
| 31 | updatedAt: new Date(), |
| 32 | }) |
| 33 | .where(eq(webhook.id, webhookId)) |
| 34 | .returning({ failedCount: webhook.failedCount }) |
| 35 | |
| 36 | const newFailedCount = result[0]?.failedCount || 0 |
| 37 | if (newFailedCount >= MAX_CONSECUTIVE_FAILURES) { |
| 38 | await db |
| 39 | .update(webhook) |
| 40 | .set({ |
| 41 | isActive: false, |
| 42 | updatedAt: new Date(), |
| 43 | }) |
| 44 | .where(eq(webhook.id, webhookId)) |
| 45 | |
| 46 | logger.warn( |
| 47 | `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures` |
| 48 | ) |
| 49 | } |
| 50 | } catch (err) { |
| 51 | logger.error(`Failed to mark webhook ${webhookId} as failed:`, err) |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | /** Reset the webhook's failure count on successful poll. */ |
| 56 | export async function markWebhookSuccess(webhookId: string, logger: Logger): Promise<void> { |
no test coverage detected