Scriba.Info (Scriba v0.1.4)

Copy Markdown View Source

Snapshot of a projection's runtime state, returned by Scriba.info/2.

Population

All fields are populated when Scriba.info/2 finds a registered Coordinator: :name, :version and the position fields (:safe_position, :stream_positions) come from the position cache; :status, :source and :target come from the Coordinator's status call. When no Coordinator is registered, Scriba.info/2 returns {:error, :not_found} rather than a partially-populated struct.

:status is one of :initializing | :running | :paused | :draining | :halted | :stopped. :source and :target are the {module, opts} specs the projection was started with.

:halted is the one to alert on

A halted projection hit a commit failure that neither replaying nor dead-lettering can resolve — a missing column, a missing privilege, or a batch in which every attempted write failed on integrity grounds. It has stopped acknowledging events and will not move again until the cause is fixed and the projection restarted. Nothing is lost: no event is acknowledged and no cursor advances.

:halt_reason carries the underlying error — usually a Postgrex.Error whose SQLSTATE names the cause, or {:integrity_wipeout, n} when a whole batch failed on integrity grounds — and is nil in every other state. Polling status is enough to detect it — you do not have to have been subscribed to [:scriba, :projection, :halted] at the instant it fired.

:safe_position is introspection, not a replay point

It is the minimum across the streams currently in the position cache — a rough "how far behind is the laggard" figure. It reads too high in two ways: the cache preloads at most 10,000 streams, and streams this projection has never written to contribute nothing at all. Do not resume a replica from it. A real replay point is v0.3 work and needs an uncapped MIN(position) aggregate against Postgres.

Truncation

When a projection has more than 1000 distinct streams, :stream_positions becomes :truncated rather than a giant map. There is no option to scope the lookup to specific streams; callers needing per-stream positions past that threshold read scriba_positions directly. :safe_position is always populated regardless of truncation.

Summary

Types

t()

@type t() :: %Scriba.Info{
  halt_reason: term() | nil,
  name: String.t(),
  safe_position: non_neg_integer(),
  source: tuple() | nil,
  status: atom() | nil,
  stream_positions:
    %{required(String.t()) => non_neg_integer()} | :truncated | nil,
  target: tuple() | nil,
  version: pos_integer()
}