Accrue.Dunning.Engine.Oban (accrue v1.3.0)

Copy Markdown View Source

Built-in dunning engine backed by Oban (DUN-03, D-02).

This is the always-on default engine. No additional configuration is required — it wraps the existing Oban-backed Accrue.Workers.DunningStep worker. It is the value Accrue.Config.dunning_engine/0 returns when no explicit engine is configured.

Responsibilities

  • start_campaign/3 — enqueues the day-0 DunningStep job for the configured after_days: 0 step (or no-ops when none is configured).
  • cancel_campaign/3 — bulk-cancels all DunningStep jobs keyed on subscription_id + campaign_started_at. Always returns :ok even on failure (the anchor-clear is already committed; the per-step cancel-guard backstops any step that races this cancel — D-12 contract).

Isolation

This module only references always-on dependencies (Oban, Accrue.Workers.DunningStep, Accrue.Config) and compiles and loads unconditionally, whether or not the optional :chimeway dependency is present. No Chimeway references appear here.

Summary

Functions

Bulk-cancels all Accrue.Workers.DunningStep Oban jobs matching sub.id + iso_anchor.

Enqueues the day-0 DunningStep job for the configured after_days: 0 step, threading the campaign anchor and invoice_id from opts.

Functions

cancel_campaign(sub, iso_anchor, opts)

Bulk-cancels all Accrue.Workers.DunningStep Oban jobs matching sub.id + iso_anchor.

Always returns :ok — a cancel failure is logged as a warning but never propagated (D-12). The anchor-clear is already committed at the time this is called; the per-step cancel-guard backstops any job that races this bulk cancel.

start_campaign(sub, anchor, opts)

Enqueues the day-0 DunningStep job for the configured after_days: 0 step, threading the campaign anchor and invoice_id from opts.

Returns :ok immediately when no day-0 step is configured (the first cadence step has after_days > 0). The DunningStep unique contract (D-16) backstops the atomic campaign-start elector against duplicate enqueues.

Note: emit_campaign_started/1 (telemetry + ledger) is NOT called here — it is Accrue's responsibility and is called in default_handler.ex BEFORE this dispatch (RESEARCH Pitfall 3).