# `Outboxer.Relay.Oban`
[🔗](https://github.com/epinault/outboxer/blob/v0.1.0/lib/outboxer/relay/oban.ex#L2)

Relays messages into [Oban](https://hex.pm/packages/oban) as jobs.

This module only exists when `:oban` is in your dependencies.

    {Outboxer,
     repo: MyApp.Repo,
     outboxes: [
       emails: [relay: {Outboxer.Relay.Oban, worker: MyApp.Workers.SendEmail, job_opts: [queue: :mailers]}]
     ]}

## Options

* `:worker` - Required. The `Oban.Worker` module that handles the message, or a function taking the envelope and returning one.

* `:oban` (`t:atom/0`) - Name of the Oban instance to insert into. The default value is `Oban`.

* `:payload` - How the payload is placed in the job args under `"payload"`. `:json` decodes it (use with the default message encoding), `:raw` passes the string through, `:base64` encodes binary payloads. The default value is `:json`.

* `:args` - A function taking the envelope and returning the job args map. Replaces the default args entirely. The default value is `nil`.

* `:job_opts` - Options for `c:Oban.Worker.new/2` (`:queue`, `:priority`, `:max_attempts`, ...), or a function taking the envelope and returning them. The default value is `[]`.

## Job args

Unless you pass `:args`, a job gets:

    %{
      "id" => "emails-42",            # Outboxer.Envelope.dedup_id/1
      "type" => "MyApp.Events.Welcome",
      "group_key" => "user:7",        # or nil
      "headers" => %{},
      "payload" => %{"user_id" => 7}  # see the :payload option
    }

## Do you need an outbox in front of Oban?

Often you do not. `Oban.insert/2` inside your own transaction is already
transactional when Oban uses the same repo, and it is one moving part
fewer. Reach for this relay when:

  * Oban lives in a **different database** than the business data, so the
    job insert cannot join your transaction.
  * You want jobs enqueued **in order** per group (see below).
  * Your code publishes domain messages and should not know which of them
    end up as jobs, in Kafka, or both.

## Guarantees

When Outboxer and Oban use the same Postgres repo, the job insert joins
the batch transaction: jobs are inserted and outbox rows removed
atomically, so a message becomes exactly one job. In every other setup
(different repos, SQLite) the handoff is at-least-once and a job may be
inserted twice; add an Oban `unique` constraint on the `"id"` arg through
`:job_opts` if that matters.

## Ordering

Outboxer inserts jobs in order, so job ids follow message order within a
group. Oban executes them in that order only when the queue runs one job
at a time (`queues: [mailers: 1]`) on a single node, or with Oban Pro's
partitioned queues. With ordinary concurrency, jobs run in parallel.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
