Scriba (Scriba v0.1.0)

Copy Markdown View Source

Public API surface for Scriba projections.

The five-line API

defmodule MyApp.Projections.Orders do
  use Scriba.Projection,
    name: "orders",
    source: {Scriba.Source.Commanded, application: MyApp.CommandedApp},
    target: {Scriba.Target.Ecto, repo: MyApp.Repo},
    parallelism: 16

  def handle(_event, _meta), do: :skip
end

{:ok, _pid} = Scriba.start_projection(MyApp.Projections.Orders)
Scriba.info(MyApp.Projections.Orders)
Scriba.pause(MyApp.Projections.Orders)
Scriba.resume(MyApp.Projections.Orders)
Scriba.stop(MyApp.Projections.Orders)
Scriba.list()

Every public function accepts either:

  • Module formScriba.pause(MyApp.Projections.Orders). The module's __scriba_config__/0 (generated by use Scriba.Projection) provides name and version. Refactor- friendly: rename the module, the call site renames with it.
  • String formScriba.pause("orders", 1). Operator-friendly when you only know the projection's name. Defaults to version 1 for the arity-1 calls.

Scriba.list/0 enumerates running projections via Scriba.Registry.

Summary

Functions

Returns a snapshot of the projection's runtime state. See Scriba.Info for the shape.

See info/1. Takes explicit name (string) and version (integer).

Returns running projections as [%{name, version, state}].

Pauses a running projection — the source stops yielding new events. In-flight events already in Pipeline processors or batchers continue through their commit lifecycle.

See pause/1. Takes explicit name (string) and version (integer).

Resumes a paused projection.

Starts a projection from its module's compile-time config.

Same as start_projection/1, but merges overrides into the module's compile-time config before starting.

Stops a running or paused projection. Waits for in-flight Broadway shutdown to complete before returning.

Functions

info(module_or_name)

@spec info(module() | String.t()) :: {:ok, Scriba.Info.t()} | {:error, :not_found}

Returns a snapshot of the projection's runtime state. See Scriba.Info for the shape.

Accepts either a projection module or a (name, version) pair. The arity-1 string form defaults to version 1.

Returns {:error, :not_found} if no Coordinator is registered for the given identity.

When the projection has more than 1000 distinct streams, :stream_positions is :truncated rather than a giant map; :safe_position is always populated regardless.

:safe_position is the minimum across cached streams — an introspection figure, not a replay point. See Scriba.Info for why it reads high and what it is not safe to build on.

The :status field is one of :initializing | :running | :paused | :draining | :stopped. :initializing is the brief window between Coordinator start and Broadway producer registration; transitions to :running automatically.

info(name, version)

@spec info(String.t(), pos_integer()) :: {:ok, Scriba.Info.t()} | {:error, :not_found}

See info/1. Takes explicit name (string) and version (integer).

list()

@spec list() :: [%{name: String.t(), version: pos_integer(), state: atom()}]

Returns running projections as [%{name, version, state}].

Enumerates Coordinators registered in Scriba.Registry; includes projections in any state, including :stopped (terminal Coordinators that haven't been terminated from the supervision tree). Empty list when no projections are running.

pause(module_or_name)

@spec pause(module() | String.t()) :: :ok | {:error, {:invalid_state, atom()}}

Pauses a running projection — the source stops yielding new events. In-flight events already in Pipeline processors or batchers continue through their commit lifecycle.

Accepts either a projection module or a name string. Arity-1 string form defaults to version 1; see pause/2 for explicit version.

Return values

  • :ok — pause signal sent to the source. The source's handle_info/2 will run on its own schedule; by the time this function returns the signal is in the source's mailbox but the source may not yet have flipped its internal flag. Operators should NOT assume "no commits possible" the instant pause/1 returns.

  • {:error, {:invalid_state, state}} — projection is not in a state where pause makes sense. The inner atom is the projection's current state:

    • :initializing — engine starting up; retry once info/1 reports :running.
    • :paused — already paused. No idempotency — callers wanting "make sure this is paused" semantics check info/1 first or pattern-match this error case as success.
    • :stopped — terminal state.
    • :draining — stop in progress.

pause(name, version)

@spec pause(String.t(), pos_integer()) :: :ok | {:error, {:invalid_state, atom()}}

See pause/1. Takes explicit name (string) and version (integer).

resume(module_or_name)

@spec resume(module() | String.t()) :: :ok | {:error, {:invalid_state, atom()}}

Resumes a paused projection.

Accepts a module or name string; same dispatch semantics as pause/1.

Return values

  • :ok — resume signal sent. Same asynchrony caveat as pause/1: first commit follows whenever the source's handle_info/2 runs and Broadway's processor stage drains accumulated demand.

  • {:error, {:invalid_state, state}} — projection is not paused. :running is not idempotent here either.

resume(name, version)

@spec resume(String.t(), pos_integer()) :: :ok | {:error, {:invalid_state, atom()}}

See resume/1.

start_projection(module)

@spec start_projection(module()) :: {:ok, pid()} | {:error, :already_started | term()}

Starts a projection from its module's compile-time config.

Reads the projection's __scriba_config__/0 map (generated by use Scriba.Projection) and starts a Scriba.Projection.Supervisor under Scriba.Projections.Supervisor. Returns the per-projection supervisor pid.

Returns immediately (does not wait for the Coordinator to transition from :initializing to :running). Wait for the [:scriba, :projection, :started] telemetry event or poll Scriba.info/1 if you need a confirmation point.

Returns {:error, :already_started} if a projection with the same (name, version) is already running.

start_projection(module, overrides)

@spec start_projection(
  module(),
  keyword()
) :: {:ok, pid()} | {:error, :already_started | term()}

Same as start_projection/1, but merges overrides into the module's compile-time config before starting.

Useful for runtime tuning of :parallelism, :batch_size, :retry, etc. per-environment without recompiling the module.

Rejects :name and :version overrides with ArgumentError. Identity is compile-time: passing a different name/version at runtime would silently create a different projection rather than override the existing one's config, which is almost certainly a bug. If you want a second projection with a different version, declare a second module with version: 2 in its use.

stop(module_or_name)

@spec stop(module() | String.t()) :: :ok | {:error, {:invalid_state, atom()}}

Stops a running or paused projection. Waits for in-flight Broadway shutdown to complete before returning.

Returns :ok on success, {:error, {:invalid_state, state}} if the projection is :initializing, :stopped, or :draining.

stop(name, version)

@spec stop(String.t(), pos_integer()) :: :ok | {:error, {:invalid_state, atom()}}

See stop/1.