Webhook Service
Webhook delivery system with event subscriptions, retry logic, and Redis event consumption
Webhook Service (Port 8007)
The webhook-service manages webhook subscriptions, delivers events to external URLs, and handles retry logic.
Database
Database: webhook_db
| Table | Purpose |
|---|---|
webhook_subscriptions | Webhook endpoint configurations |
webhook_deliveries | Delivery attempt records |
API Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /webhooks | List webhooks |
| POST | /webhooks | Create webhook |
| DELETE | /webhooks/{id} | Delete webhook |
| POST | /webhooks/{id}/test | Test webhook delivery |
| GET | /webhooks/{id}/deliveries | List delivery history |
Event Consumption
The webhook-service subscribes to the Redis webhook:events channel and processes events asynchronously:
@celery_app.task
async def process_webhook_event(event_data: dict):
webhooks = await webhook_repo.find_by_event_type(
event_data["event_type"],
event_data["tenant_id"]
)
for webhook in webhooks:
await deliver_webhook(webhook, event_data)Retry Logic
Failed deliveries are retried with exponential backoff:
RETRY_SCHEDULE = [60, 300, 900, 3600, 21600] # 1m, 5m, 15m, 1h, 6h
async def deliver_webhook(webhook, event):
for attempt, delay in enumerate(RETRY_SCHEDULE):
try:
async with httpx.AsyncClient() as client:
resp = await client.post(webhook.url, json=event, timeout=30)
if resp.status_code < 500:
return # Success
except Exception:
pass
await asyncio.sleep(delay)The webhook-beat Celery Beat container retries pending webhooks every 1 minute.
Supported Events
The service consumes events from survey-service and data-service:
survey.created,survey.updated,survey.deleted,survey.published,survey.unpublishedresponse.submitted,response.deleted,response.invalidated
