Public facade for the Outbox transactional event bus.
Producers call publish/2 from inside their domain transactions to
emit events that subscribers (registered in application config) react
to via Outbox.SubscriberJob after the dispatcher fans them out.
See Outbox.Subscriber for the subscriber contract and the README for
the full architecture overview.
Summary
Types
Event name. Convention: <entity>.<past-tense-verb> (lowercase, dot-separated).
JSON-serializable payload. Atom keys are converted to strings on insert.
Functions
Returns a Supervisor child_spec for Outbox.Application.
Clears the current process's ambient context.
Returns the current process's ambient context map (defaults to %{}).
Publish a domain event.
Merge map into the ambient context for the current process.
Types
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
Returns a Supervisor child_spec for Outbox.Application.
@spec clear_context() :: :ok
Clears the current process's ambient context.
@spec get_context() :: map()
Returns the current process's ambient context map (defaults to %{}).
@spec publish(name(), payload(), keyword()) :: {:ok, Outbox.OutboxEvent.t()} | {:ok, :sampled_out | :transient} | {:error, Ecto.Changeset.t()} | {:error, {:schema, term()}}
Publish a domain event.
This function performs a single Repo.insert/1 and does not open
its own transaction. The caller is responsible for wrapping the
domain write and the publish/2 call in Repo.transaction/1 if
atomicity-with-the-domain-write is required (it almost always is).
Atom keys in the payload are converted to strings so subscribers always see string keys (consistent with what JSONB round-trips produce).
Options
:context— opaque map merged over the ambient process context (seeput_context/1).:sample— float in0.0..1.0. The event is kept with this probability; when dropped, nothing is persisted or broadcast and{:ok, :sampled_out}is returned. For high-volume telemetry.:transient— whentrue, the event is not persisted: it is broadcast to the configured PubSub (if any) and{:ok, :transient}is returned. No row, no Oban fan-out, no delivery guarantee — for loss-tolerant signals only, never an audit system of record.
If a validator is registered for this event name (see
Outbox.Config.schemas/0), the stringified payload is validated first;
a failure returns {:error, {:schema, reason}} and nothing is persisted
or broadcast.
Examples
Repo.transaction(fn ->
{:ok, product} = Repo.insert(changeset)
{:ok, _event} = Outbox.publish("product.created", %{"id" => product.id})
product
end)
@spec put_context(map()) :: :ok
Merge map into the ambient context for the current process.
The ambient context is attached to every event published from this
process (unless a per-call :context overrides a key). Set it once
per request (e.g. in a plug or LiveView on_mount) so callers don't
thread context through every publish/3. The library treats the map
as opaque — hosts decide its keys (e.g. actor_id, actor_type).
Atom keys are stringified.