# `Accrue.Webhook.DispatchWorker`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v1.0.0/lib/accrue/webhook/dispatch_worker.ex#L1)

Oban worker for async webhook handler dispatch.

Enqueued by `Accrue.Webhook.Ingest` in the same transaction as the
webhook event row. Loads the `WebhookEvent`, projects it to
`%Accrue.Webhook.Event{}`, and dispatches to the handler chain.

## Handler context (`ctx`)

Besides `attempt`, `max_attempts`, `webhook_event_id`, and `endpoint`, the
map includes `:meter_error_object` — the raw Stripe map at
`row.data["data"]["object"]` when present (else `%{}`). Meter error
handlers read this key so `handle_event/3` can extract usage identifiers
without re-parsing the full signing payload.

## Dispatch order

1. `Accrue.Webhook.DefaultHandler` runs first (non-disableable).
   Connect-scoped events route to `Accrue.Webhook.ConnectHandler`.
2. User handlers from `Accrue.Config.webhook_handlers/0` run sequentially.
3. Each handler is rescue-wrapped for crash isolation — a user handler
   crash is logged and emits telemetry, but does not cause a retry.

## Retry policy

25 attempts with exponential backoff. On the final attempt, transitions
the webhook event to `:dead` status and emits
`[:accrue, :ops, :webhook_dlq, :dead_lettered]` telemetry. Dead-lettered
events can be replayed via `Accrue.Webhooks.DLQ.requeue/1`.

## Status lifecycle

    :received -> :processing -> :succeeded
                              -> :failed (retryable)
                              -> :dead (final attempt)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
