# `Mailglass.Webhook.Pruner`
[🔗](https://github.com/szTheory/mailglass/blob/v0.1.0/lib/mailglass/webhook/pruner.ex#L2)

Oban cron worker that prunes `mailglass_webhook_events` rows by
status + age (CONTEXT D-16).

Three retention knobs (per `Mailglass.Config :webhook_retention`):

  * `:succeeded_days` (default 14) — prune `:succeeded` rows older
    than N days
  * `:dead_days` (default 90) — prune `:dead` (terminal-after-retries)
    rows older than N days
  * `:failed_days` (default `:infinity`) — `:failed` rows are
    investigatable; never pruned by default

Set any knob to `:infinity` to disable that prune class — the worker
returns `{:ok, 0}` for that status WITHOUT issuing the DELETE.

## Cron cadence

Daily is sufficient — retention is days-scale, so running hourly adds
DB churn without changing outcomes. Adopters wire the cron in their
own Oban config (`0 3 * * *` — 3 AM UTC is the recommended default;
lands with Plan 04-09 guides/webhooks.md).

## Optional-dep gating

The entire module is conditionally compiled at file top level behind
`if Code.ensure_loaded?(Oban.Worker)`. When Oban is absent, a stub
module is defined that exposes `available?/0 → false`;
`Mailglass.Application` emits a consolidated `Logger.warning` at boot
(D-20) directing operators to run `mix mailglass.webhooks.prune` from
their own cron infrastructure.

## GDPR erasure

Targeted DELETE on `mailglass_webhook_events.raw_payload->>'to' = ?`
is the GDPR path (D-15) — handled by adopter ad-hoc via
`Mailglass.Repo.delete_all/2`, NOT this Pruner. The Pruner's
DELETEs are retention-policy-driven (status + age), not identity-driven.

## Telemetry

Emits `[:mailglass, :webhook, :prune, :stop]` with measurements
`%{succeeded_deleted: n, dead_deleted: m}` and metadata
`%{status: :ok}` per CONTEXT D-22 + D-23 whitelist.

# `available?`
*since 0.1.0* 

```elixir
@spec available?() :: boolean()
```

Returns `true` when the Pruner module is fully compiled (Oban
available). Used by `mix mailglass.webhooks.prune` and the
Application boot-warning.

# `prune`

```elixir
@spec prune() :: {:ok, %{succeeded: non_neg_integer(), dead: non_neg_integer()}}
```

Run the prune sweep. Returns `{:ok, %{succeeded: n, dead: m}}`.

Exposed as a public function so `mix mailglass.webhooks.prune`
invokes the same code path, and so ops engineers can trigger an
out-of-band prune without waiting for the next cron tick.

---

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