Each target TYPE is now an implementation of a Target interface,
dispatched from a registry in processDelivery instead of a type
switch on TargetType. Every target owns its full delivery,
including durable retries.
- Target.Deliver receives the context, the per-webhook DB, the
Delivery, the attempt Task, and a Scheduler for durable
re-enqueue (the existing timer + retry queue). The target makes
one attempt, records the DeliveryResult, updates DeliveryStatus,
and — for retry targets — decides whether to retry, computes its
own backoff, gates with its own circuit breaker, and reschedules
via the Scheduler.
- httpTarget and slackTarget share a retry core (retry, backoff,
circuit breaker). database and log targets are fire-and-forget.
- Slack retry/breaker is gated on MaxRetries: 0 stays
fire-and-forget (existing Slack targets unchanged), >0 gets
retry + backoff + breaker on the shared core.
- The engine keeps only the worker pool, queue/channels, restart
recovery/sweep, the recordResult/updateDeliveryStatus helpers,
and ScheduleRetry. Recovery/sweep hand each orphaned retrying
delivery back to its target to recompute the backoff.
- The log target logs the entire inbound webhook: full body and
headers, method, content type, and the webhook and entrypoint
ids (supersedes the smaller log-summary work).
- Task gains EntrypointID, populated in the webhook handler, the
recovery-task builder, and buildEventFromTask.
Behaviour is preserved: existing delivery tests pass with their
export_test wrappers re-pointed at the new targets; new pure
Deliver tests cover the log full-content output and the gated
Slack retry path.