AshDispatch.Transport behaviour (AshDispatch v0.5.1)
View SourceBehaviour for AshDispatch transports.
Before this behaviour, adding a new transport (e.g. :oban) required
edits in 3-4 places in AshDispatch.Dispatcher:
- The
dispatch_to_transport/4case statement (routing) - The
skip_receipt_for_transport?/1truth table - The moduledoc transport list
- (Optionally) tests against any of the above
With this behaviour, each transport uses the macro with its atom +
receipt-skip declaration, and AshDispatch.Transport.Registry
aggregates them at compile time. The dispatcher's case statement
becomes a single registry lookup; adding a transport is one new
file + one entry in the registry's module list.
Implementing
defmodule MyApp.Transports.Foo do
use AshDispatch.Transport, atom: :foo, skip_receipt?: false
def deliver(receipt, context, channel, event_config) do
# ... transport-specific work
{:ok, updated_receipt}
end
endBoth transport_atom/0 and skip_receipt?/0 are generated by the
macro and defoverridable, so subclasses can override either if a
transport's receipt-skip behaviour is conditional (rare).
Receipt-skip semantics
skip_receipt?: true means the transport is "lightweight" — no
DeliveryReceipt row is created when this channel fires. Used by
:broadcast (the audit trail is the PubSub log) and :oban (the
audit trail is the enqueued oban_jobs row).
Lightweight transports receive a pseudo-receipt in deliver/4:
%{id: nil, ...}. They should NOT call Ash.update on the
pseudo-receipt; instead return {:ok, Map.put(receipt, :status, :sent | :skipped)}.
Summary
Callbacks
Deliver an event payload to a recipient/channel.
Event metadata keys this transport REQUIRES at the event-registration
layer (F4). ValidateChannels enforces presence at compile-time —
an event registering a [transport: :oban] channel must declare
metadata: [oban_worker: ...] or the DSL fails with a precise
Spark.Error.DslError pointing at the registration site.
Whether to skip DeliveryReceipt creation for this transport.
Defaults to false (Receipt + status-tracking is the default
semantics; opt out only for transports where another artifact
IS the audit trail — see :broadcast / :oban).
The transport atom this module handles (e.g. :oban, :broadcast).
Callbacks
@callback deliver( receipt :: map(), context :: map(), channel :: map(), event_config :: keyword() ) :: {:ok, map()} | {:error, term()}
Deliver an event payload to a recipient/channel.
Returns {:ok, receipt} on success (the receipt may be updated to
reflect terminal status) or {:error, reason}. Errors propagate to
Dispatcher.dispatch_to_transport/4 which logs + folds them into
the per-recipient verdict; the dispatcher itself absorbs errors so
one transport's failure doesn't block the others on the same event.
@callback required_event_metadata_keys() :: [atom()]
Event metadata keys this transport REQUIRES at the event-registration
layer (F4). ValidateChannels enforces presence at compile-time —
an event registering a [transport: :oban] channel must declare
metadata: [oban_worker: ...] or the DSL fails with a precise
Spark.Error.DslError pointing at the registration site.
Defaults to [] (no required keys). :oban overrides to [:oban_worker].
Optional — transports that don't need event metadata return [].
@callback skip_receipt?() :: boolean()
Whether to skip DeliveryReceipt creation for this transport.
Defaults to false (Receipt + status-tracking is the default
semantics; opt out only for transports where another artifact
IS the audit trail — see :broadcast / :oban).
@callback transport_atom() :: atom()
The transport atom this module handles (e.g. :oban, :broadcast).