feat(phase-3): workstream 5 — Webhooks & Event Streaming
- DB migrations 016/017: webhook_subscriptions and webhook_deliveries tables - WebhookService: CRUD for subscriptions, Vault-backed secret storage, delivery history - WebhookDeliveryWorker: Bull queue, HMAC-SHA256 signatures, exponential backoff, SSRF protection (RFC 1918 + loopback + link-local rejection), dead-letter handling - EventPublisher: publishes 10 event types (agent/credential/token lifecycle); optional Kafka adapter activated via KAFKA_BROKERS env var - AgentService, CredentialService, OAuth2Service: wired to EventPublisher - WebhookController + routes: 6 endpoints with webhooks:read / webhooks:write scope guards - KafkaAdapter: optional Kafka producer (kafkajs), no-op when KAFKA_BROKERS unset - OAuthScope extended: webhooks:read, webhooks:write - AuditAction extended: webhook.created, webhook.updated, webhook.deleted - Metrics: agentidp_webhook_dead_letters_total counter added to registry - 523 unit tests passing; TypeScript strict throughout, zero `any` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -77,3 +77,15 @@ export const redisCommandDurationSeconds = new Histogram({
|
||||
buckets: [0.0005, 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25],
|
||||
registers: [metricsRegistry],
|
||||
});
|
||||
|
||||
/**
|
||||
* Total number of webhook deliveries that reached the dead-letter state
|
||||
* (i.e. exhausted all retry attempts without a 2xx response).
|
||||
* Labels: organization_id
|
||||
*/
|
||||
export const webhookDeadLettersTotal = new Counter({
|
||||
name: 'agentidp_webhook_dead_letters_total',
|
||||
help: 'Total number of webhook deliveries that exhausted all retry attempts.',
|
||||
labelNames: ['organization_id'] as const,
|
||||
registers: [metricsRegistry],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user