Oban cron worker for BILL-15 / D4-02 dunning grace-period overlay.
Stripe Smart Retries owns the retry cadence. Accrue owns a thin
grace-period overlay on top: once past_due_since is older than the
configured grace_days, this worker asks the processor facade to
move the subscription to the terminal action (:unpaid or
:canceled) and stamps dunning_sweep_attempted_at on success.
Canonicality (D2-29)
This worker NEVER flips the local subscription.status. It only:
- Calls
Accrue.Processor.update_subscription/3to ask the processor facade to transition the row. - Stamps
dunning_sweep_attempted_atAFTER a successful processor call so the same row is not retried on the next tick. - Records a
dunning.terminal_action_requestedaudit event inaccrue_events.
The actual local status flip happens when Stripe echoes the change
back via customer.subscription.updated, which the
Accrue.Webhook.DefaultHandler picks up and projects.
Host wiring
Accrue does not start its own Oban instance. The host app must wire the cron themselves:
config :my_app, Oban,
queues: [accrue_dunning: 2],
plugins: [
{Oban.Plugins.Cron,
crontab: [{"*/15 * * * *", Accrue.Jobs.DunningSweeper}]}
]Failure handling
A processor error on any row logs a warning and returns false
WITHOUT stamping dunning_sweep_attempted_at, so the next cron tick
picks the same row up again. max_attempts: 3 on the worker bounds
per-tick retries.
Summary
Functions
@spec sweep() :: {:ok, non_neg_integer()}
Runs one sweep tick. Returns {:ok, count} where count is the
number of subscriptions successfully transitioned this tick.