Helpers for the scriba_dead_letters table — failed events recorded for
later inspection or replay.
An event arrives here in five ways (§9). Two are handler failures, after retry exhaustion:
- The handler returned
{:error, reason}. - The handler raised — the engine catches it and tags it
{:exception, exception, stacktrace}.
Three more bypass the retry layer entirely, because retrying them changes nothing:
- The commit failed with an integrity-class error, isolated by the
per-event fallback pass (
{:commit_error, reason}). - The handler returned a
{:multi, _}whose operation names collide with another event's in the same batch ({:multi_key_collision, keys}). - The handler returned a shape the target cannot apply.
All of them end up routed to a row in scriba_dead_letters with a serialized
copy of the event and an error description. Per §9.2, the projection's
position advances past the dead-lettered event — the projection does not
block. There is no replay function yet; replaying means reading the row and
re-dispatching the event yourself.
Transient and structural commit failures are not dead-letter paths: a
transient one replays the whole batch, a structural one halts the
projection. See Scriba.Target.
This module exposes raw helpers; the routing decision (when to insert) lives
in the Pipeline, which partitions failure-shape handler results out of the
batch and passes them to the target as dead_letters.
Summary
Functions
Builds a row map for the scriba_dead_letters table from a failing event
and an error tuple/exception.
Inserts a single dead-letter row directly via repo. Used by callers that
manage their own transaction (e.g. retry-then-dead-letter flows).
Appends a dead-letter insert to an Ecto.Multi. Useful for the Pipeline's
"dead-letter and advance position" transaction after a target apply_batch
has already failed and rolled back.
Types
@type projection() :: %{name: String.t(), version: pos_integer()}
Functions
@spec build_row(projection(), Scriba.Event.t(), term()) :: map()
Builds a row map for the scriba_dead_letters table from a failing event
and an error tuple/exception.
Accepts:
{:error, reason}—kind = "error",message = inspect(reason){:exception, exception, stacktrace}—kindis the exception module as a string, message + formatted stacktrace{:commit_error, reason}—kind = "commit:<SQLSTATE label>"{:multi_key_collision, keys}—kind = "multi_key_collision"- anything else —
kind = "invalid_return"
@spec insert(module(), projection(), Scriba.Event.t(), term()) :: {:ok, term()} | {:error, term()}
Inserts a single dead-letter row directly via repo. Used by callers that
manage their own transaction (e.g. retry-then-dead-letter flows).
@spec multi(Ecto.Multi.t(), projection(), Scriba.Event.t(), term()) :: Ecto.Multi.t()
Appends a dead-letter insert to an Ecto.Multi. Useful for the Pipeline's
"dead-letter and advance position" transaction after a target apply_batch
has already failed and rolled back.