Scriba.Info (Scriba v0.1.3)

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. 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 (typically a Postgrex.Error whose SQLSTATE names the cause) 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()
}