Chimeway.Dispatch.ObanWorker (chimeway v1.0.0)

Copy Markdown View Source

Oban worker that performs a single Chimeway delivery by delivery_id.

Job args contain only delivery_id (UUID string). Full payload is never stored in Oban job args — the delivery row is the source of truth.

Transactional enqueue

Insert this worker's job inside the same Ecto.Multi as delivery row creation:

alias Chimeway.Dispatch.ObanWorker

Ecto.Multi.new()
|> Ecto.Multi.insert(:delivery, delivery_changeset)
|> Oban.insert(:job, ObanWorker.new(%{delivery_id: delivery.id}))
|> Chimeway.Repo.transaction()

Rolling back the Ecto.Multi also rolls back the job — no orphaned jobs.

Idempotency and terminal-state short-circuit

The worker checks delivery terminal states (via Chimeway.Deliveries.terminal_states/0) on every execution. A delivery already in :succeeded, :suppressed, or :cancelled returns :ok immediately with no adapter call and no new attempt row.

Phase 14 retry contract (REL-02 / REL-03)

OSS Oban 2.21.1 has no exhausted callback. This worker uses an in-band attempt == max_attempts guard inside perform/1 to know when it has reached the final retry — that is the moment the durable :cancelled retries_exhausted state is written via Deliveries.exhaust_delivery/1.

Return-value contract:

  • Successful delivery -> :ok.
  • Permanent / bounced failure -> :ok (record_attempt already converged the delivery to :cancelled with the appropriate suppression_reason; Oban does not retry).
  • Transient failure with retries remaining (attempt < max_attempts) -> {:error, reason}; Oban schedules a retry under its default exponential- with-jitter Oban.Worker.backoff/1.
  • Transient failure on the final attempt (attempt == max_attempts) -> Deliveries.exhaust_delivery/1 writes the :cancelled retries_exhausted terminal state, then this function returns :ok so the Oban job is marked :completed instead of :discarded (RESEARCH Pitfall 1: keeps operator telemetry dashboards clean — the durable explanation lives on the delivery row, not on the Oban job).