Orkestra.EventStore.EventStoreDB (orkestra v0.2.3)

Copy Markdown View Source

EventStoreDB adapter via Spear gRPC client.

Requires Spear.Connection in the supervision tree.

Configuration

config :orkestra, Orkestra.EventStore.EventStoreDB,
  connection_string: "esdb://localhost:2113?tls=false"

Summary

Functions

Subscribes subscriber to receive events from stream_id_or_all starting after from_position (exclusive).

Cancels the subscription identified by handle (the relay pid returned by subscribe_from_position/3) and stops delivery.

Functions

subscribe_from_position(stream_id_or_all, from_position, subscriber)

@spec subscribe_from_position(
  Orkestra.EventStore.stream_id() | :all,
  integer(),
  pid()
) :: {:ok, pid()} | {:error, term()}

Subscribes subscriber to receive events from stream_id_or_all starting after from_position (exclusive).

The from_position is translated by map_subscribe_from/2 (see there for the full mapping and rationale):

  • -1 / nil:start (replay from the beginning, exactly once).
  • :all + a non-negative commit_position → a %Spear.Filter.Checkpoint{} (a raw integer cannot be used for :all — Spear would raise FunctionClauseError in map_all_position/1).
  • a named stream + a non-negative revision → the integer revision.

All non-:start forms are exclusive in Spear: from: N delivers only events strictly after N, matching the D-01 monotonic contract, InMemory's semantics, and the exactly-once projector — resuming from a saved checkpoint never re-delivers the event at that checkpoint, so no manual skip is required.

Delivery shape (parity with InMemory)

Delivery does not hand subscriber the raw %Spear.Event{} structs that Spear.subscribe/4 pushes. Instead a Orkestra.EventStore.EventStoreDB.SubscriptionRelay process sits between Spear and subscriber and delivers stored_event_with_position() maps — %{id, type, data, metadata, stream_revision, global_position}, the same shape produced by load_events/1,2 and the same shape delivered by Orkestra.EventStore.InMemory. That is exactly what Orkestra.Projector.GenServer.handle_info/2 pattern-matches on (%{global_position: _}); handed raw Spear structs it would match nothing. The relay also drops Spear's control messages (%Spear.Filter.Checkpoint{}, {:caught_up, _}, {:fell_behind, _}) which the projector has no clause for, and applies the link-de-duplication subscription options (see the relay moduledoc).

The returned handle is the relay pid (an opaque subscription handle, not a Spear reference). Pass it to unsubscribe/1 to tear the subscription down; it is also torn down automatically when subscriber dies.

Returns {:ok, subscription_handle} on success or {:error, reason} on failure.

unsubscribe(handle)

@spec unsubscribe(pid()) :: :ok

Cancels the subscription identified by handle (the relay pid returned by subscribe_from_position/3) and stops delivery.

Idempotent: returns :ok whether or not the relay is still alive. The Orkestra.Projector.GenServer calls this on rebuild (to resubscribe from a reset checkpoint) and it is a no-op-safe cleanup path; on normal projector termination the relay tears itself down via its subscriber monitor, so an explicit call is not required there.