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:succeededrows older than N days:dead_days(default 90) — prune:dead(terminal-after-retries) rows older than N days:failed_days(default:infinity) —:failedrows 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.
Summary
Functions
Returns true when the Pruner module is fully compiled (Oban
available). Used by mix mailglass.webhooks.prune and the
Application boot-warning.
Run the prune sweep. Returns {:ok, %{succeeded: n, dead: m}}.
Functions
@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.
@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.