fix(webhook): offload SLA webhook dispatch to Celery task - #244
Merged
usmanimamu17-create merged 1 commit intoAug 18, 2026
Merged
Conversation
The webhook dispatcher in trigger_sla_violation_webhooks() called dispatch_delivery() synchronously in a loop, blocking the SLA computation response while outbound HTTP requests completed. When a broker is configured (task_always_eager=False), dispatches are now enqueued via the existing dispatch_webhook_delivery Celery task. Falls back to synchronous dispatch when running in eager mode or when Celery is unavailable. Also adds an idempotency guard in dispatch_delivery() to skip deliveries already in a terminal state (SUCCESS, DEAD_LETTER), preventing duplicate HTTP calls from concurrent task executions.
usmanimamu17-create
approved these changes
Aug 18, 2026
usmanimamu17-create
left a comment
Contributor
There was a problem hiding this comment.
LGTM. thanks for contributing.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #234
Offloads webhook dispatch from the synchronous call path in
trigger_sla_violation_webhooks()to the existingdispatch_webhook_deliveryCelery task. When a broker is configured (task_always_eager=False), each delivery is enqueued viaapply_asyncinstead of blocking the caller. Falls back to synchronous dispatch in eager/single-worker mode or when Celery is unavailable.Why
The webhook dispatcher called
dispatch_delivery()synchronously in a loop, blocking the SLA computation response while outbound HTTP requests completed (10s timeout each). With multiple webhooks, this caused timeout cascades. The existingdispatch_webhook_deliveryCelery task was already defined but never wired into the trigger path.What was built
app/services/webhook_service.py:dispatch_delivery()trigger_sla_violation_webhooks()dispatch_webhook_delivery.delay()when broker is configured, falls back to synchronous call otherwisetests/test_webhook_async_dispatch.py: (new)TestTriggerSlaViolationAsyncDispatchTestDispatchDeliveryIdempotencyIntegration changes outside
<module>/No existing files modified beyond
app/services/webhook_service.py. The existingdispatch_webhook_deliverytask inapp/tasks/webhook_tasks.pyandretry_pending_webhook_deliveriesbeat task remain unchanged.Acceptance criteria coverage
test_celery_dispatches_via_task_when_broker_configured— verifiesdispatch_webhook_delivery.delay()is called).delay(), not called synchronously)dispatch_webhook_deliverytask +retry_pending_webhook_deliveriesbeat task unchanged)test_celery_dispatches_via_task_when_broker_configured—dispatch_deliveryis NOT called synchronously)test_fallback_to_sync_when_eager_mode,test_fallback_to_sync_when_celery_import_fails)Deliberately deferred
WebhookDispatchLimiterandCircuitBreakerto async primitives (requires async-compatible lock/semaphore, separate concern)Test plan
pytest tests/test_webhook_async_dispatch.py— 9/9 passing (9 new tests)pytest tests/test_webhook_breaker.py tests/test_webhook_dispatch_limiter.py tests/test_webhook_ssrf.py— 20/20 passing (no regressions)Env vars / Notes
No new env vars. Uses existing
CELERY_BROKER_URLandCELERY_TASK_ALWAYS_EAGER. WhenCELERY_TASK_ALWAYS_EAGER=true(default for local dev), behavior is identical to before — dispatches are synchronous. SetCELERY_TASK_ALWAYS_EAGER=falsewith a valid Redis broker to get async offload.