PhoenixKit. Modules. Emails. EventTrackerReconciler
(phoenix_kit_emails v0.1.23)
Copy Markdown
View Source
Stateless reconcile — the single code path that starts/stops a
tracker's self-scheduling Oban chain, enforcing
EventTracker.should_run?/1. See spec §4.2/§4.3.
Not a GenServer (decision §9.1): the correctness backbone is the
periodic reconcile Cron (EventTrackerReconcileWorker), not a
long-lived orchestrator process. reconcile/0/reconcile_tracker/1
are plain functions, safe to call from anywhere (boot, a settings
toggle, the Cron tick, a future admin panel) — idempotent and
cluster-safe:
- "ensure exactly one chain" = an Oban
uniqueinsert — a genuinely dead chain gets a fresh immediate job (schedule_in: 0); a chain that's already alive (:available/:scheduled/:executing) hits the unique conflict and is left completely untouched, its ownscheduled_atunchanged (noreplace:— seeensure_chain/1's own comment for why touching it would silently override the operator's own polling interval). Enforced at the DATABASE by Oban's own uniqueness, so two nodes reconciling simultaneously cannot create two chains (spec §8a). - "ensure none" =
Oban.cancel_all_jobs/1scoped toavailable/scheduledonly (neverexecuting— a running cycle is never interrupted; it dies on its own next time it checksshould_run?/0and doesn't self-reschedule, same mechanismSQSPollingJob/BrevoPollingJobalready rely on for the disable path — see #21).
A duplicate/racing insert at worst costs one extra no-op cycle
(should_run?/0's per-cycle gate inside the job itself is the real
safety net) — never two live chains.
Summary
Functions
Reconcile every registered tracker. Returns a list of
{tracker, result} pairs, result being whatever
reconcile_tracker/1 returns for that tracker — never raises on a
single tracker's failure (one broken tracker must not stop the rest
from reconciling).
Reconcile a single tracker against EventTracker.should_run?/1.
Functions
Reconcile every registered tracker. Returns a list of
{tracker, result} pairs, result being whatever
reconcile_tracker/1 returns for that tracker — never raises on a
single tracker's failure (one broken tracker must not stop the rest
from reconciling).
@spec reconcile_tracker(module()) :: {:ok, Oban.Job.t() | :not_running} | {:error, term()}
Reconcile a single tracker against EventTracker.should_run?/1.
should_run? == true→{:ok, %Oban.Job{}}(the chain's current job — the existing one, untouched, if the chain is already alive; a freshly inserted one, running immediately, if it wasn't).should_run? == false→{:ok, :not_running}(any queued job for this tracker's worker was cancelled; a still-executingone is left to finish and die on its own).{:error, reason}on an insert/cancel failure — logged, never raised, so a single tracker's transient DB hiccup during a Cron tick doesn't take down the rest.