EventStore v0.15.1 EventStore View Source

EventStore is CQRS event store implemented in Elixir.

It uses PostgreSQL (v9.5 or later) as the underlying storage engine.

The EventStore module provides the public API to read and write events to an event stream, and subscribe to event notifications.

Please refer to the following guides to learn more:

Link to this section Summary

Functions

Acknowledge receipt of the given events received from a single stream, or all streams, subscription

Append one or more events to a stream atomically

Get the event store configuration for the environment

Delete a previously recorded snapshop for a given source

Reads the requested number of events from all streams, in the order in which they were originally written

Read a snapshot, if available, for a given source

Reads the requested number of events from the given stream, in the order in which they were originally written

Record a snapshot of the data and metadata for a given source

Streams events from all streams, in the order in which they were originally written

Streams events from the given stream, in the order in which they were originally written

Create a transient subscription to a given stream

Create a persistent subscription to all streams

Create a persistent subscription to a single stream

Unsubscribe an existing subscriber from all event notifications

Unsubscribe an existing subscriber from event notifications

Link to this section Types

Link to this type expected_version() View Source
expected_version() ::
  :any_version | :no_stream | :stream_exists | non_neg_integer()
Link to this type start_from() View Source
start_from() :: :origin | :current | non_neg_integer()

Link to this section Functions

Link to this function ack(subscription, ack) View Source
ack(
  pid(),
  EventStore.RecordedEvent.t()
  | [EventStore.RecordedEvent.t()]
  | non_neg_integer()
) :: :ok | {:error, reason :: term()}

Acknowledge receipt of the given events received from a single stream, or all streams, subscription.

Accepts a RecordedEvent, a list of RecordedEvents, or the event number of the recorded event to acknowledge.

Link to this function append_to_stream(stream_uuid, expected_version, events, timeout \\ 15000) View Source
append_to_stream(
  String.t(),
  expected_version(),
  [EventStore.EventData.t()],
  timeout() | nil
) ::
  :ok
  | {:error, :cannot_append_to_all_stream}
  | {:error, :stream_exists}
  | {:error, :stream_does_not_exist}
  | {:error, :wrong_expected_version}
  | {:error, reason :: term()}

Append one or more events to a stream atomically.

  • stream_uuid is used to uniquely identify a stream.

  • expected_version is used for optimistic concurrency checks. You can provide a non-negative integer to specify the expected stream version. This is used to ensure you can only append to the stream if it is at exactly that version.

    You can also provide one of the following values to affect the concurrency check behaviour:

    • :any_version - No concurrency checking; allow any stream version (including no stream).
    • :no_stream - Ensure the stream does not exist.
    • :stream_exists - Ensure the stream exists.
  • events is a list of %EventStore.EventData{} structs.

  • timeout an optional timeout for the database transaction, in milliseconds. Defaults to 15000ms.

Returns :ok on success, or an {:error, reason} tagged tuple. The returned error may be due to one of the following reasons:

  • {:error, :wrong_expected_version} when the actual stream version differs from the provided expected version.
  • {:error, :stream_exists} when the stream exists, but expected version was :no_stream.
  • {:error, :stream_does_not_exist} when the stream does not exist, but expected version was :stream_exists.

Get the event store configuration for the environment.

Link to this function delete_snapshot(source_uuid) View Source
delete_snapshot(String.t()) :: :ok | {:error, reason :: term()}

Delete a previously recorded snapshop for a given source.

Returns :ok on success, or when the snapshot does not exist.

Link to this function read_all_streams_forward(start_event_number \\ 0, count \\ 1000, timeout \\ 15000) View Source
read_all_streams_forward(non_neg_integer(), non_neg_integer(), timeout() | nil) ::
  {:ok, [EventStore.RecordedEvent.t()]} | {:error, reason :: term()}

Reads the requested number of events from all streams, in the order in which they were originally written.

  • start_event_number optionally, the number of the first event to read. Defaults to the beginning of the stream if not set.

  • count optionally, the maximum number of events to read. If not set it will be limited to returning 1000 events from all streams.

  • timeout an optional timeout for querying the database, in milliseconds. Defaults to 15000ms.

Link to this function read_snapshot(source_uuid) View Source
read_snapshot(String.t()) ::
  {:ok, EventStore.Snapshots.SnapshotData.t()} | {:error, :snapshot_not_found}

Read a snapshot, if available, for a given source.

Returns {:ok, %EventStore.Snapshots.SnapshotData{}} on success, or {:error, :snapshot_not_found} when unavailable.

Link to this function read_stream_forward(stream_uuid, start_version \\ 0, count \\ 1000, timeout \\ 15000) View Source
read_stream_forward(
  String.t(),
  non_neg_integer(),
  non_neg_integer(),
  timeout() | nil
) :: {:ok, [EventStore.RecordedEvent.t()]} | {:error, reason :: term()}

Reads the requested number of events from the given stream, in the order in which they were originally written.

  • stream_uuid is used to uniquely identify a stream.

  • start_version optionally, the version number of the first event to read. Defaults to the beginning of the stream if not set.

  • count optionally, the maximum number of events to read. If not set it will be limited to returning 1000 events from the stream.

  • timeout an optional timeout for querying the database, in milliseconds. Defaults to 15000ms.

Link to this function record_snapshot(snapshot) View Source
record_snapshot(EventStore.Snapshots.SnapshotData.t()) ::
  :ok | {:error, reason :: term()}

Record a snapshot of the data and metadata for a given source.

Returns :ok on success.

Link to this function stream_all_forward(start_event_number \\ 0, read_batch_size \\ 1000, timeout \\ 15000) View Source

Streams events from all streams, in the order in which they were originally written.

  • start_event_number optionally, the number of the first event to read. Defaults to the beginning of the stream if not set.

  • read_batch_size optionally, the number of events to read at a time from storage. Defaults to reading 1000 events per batch.

  • timeout an optional timeout for querying the database (per batch), in milliseconds. Defaults to 15000ms.

Link to this function stream_forward(stream_uuid, start_version \\ 0, read_batch_size \\ 1000, timeout \\ 15000) View Source
stream_forward(
  String.t(),
  non_neg_integer(),
  non_neg_integer(),
  timeout() | nil
) :: Enumerable.t() | {:error, reason :: term()}

Streams events from the given stream, in the order in which they were originally written.

  • start_version optionally, the version number of the first event to read. Defaults to the beginning of the stream if not set.

  • read_batch_size optionally, the number of events to read at a time from storage. Defaults to reading 1000 events per batch.

  • timeout an optional timeout for querying the database (per batch), in milliseconds. Defaults to 15000ms.

Link to this function subscribe(stream_uuid, opts \\ []) View Source
subscribe(String.t(),
  selector: (EventStore.RecordedEvent.t() -> any()),
  mapper: (EventStore.RecordedEvent.t() -> any())
) :: :ok | {:error, term()}

Create a transient subscription to a given stream.

  • stream_uuid is the stream to subscribe to. Use the $all identifier to subscribe to events from all streams.

  • opts is an optional map providing additional subscription configuration:

    • selector to define a function to filter each event, i.e. returns only those elements for which fun returns a truthy value
    • mapper to define a function to map each recorded event before sending to the subscriber.

The calling process will be notified whenever new events are appended to the given stream_uuid.

As the subscription is transient you do not need to acknowledge receipt of each event. The subscriber process will miss any events if it is restarted and resubscribes. If you need a persistent subscription with guaranteed at-least-once event delivery and back-pressure you should use EventStore.subscribe_to_stream/4.

Notification message

Events will be sent to the subscriber, in batches, as {:events, events} where events is a collection of EventStore.RecordedEvent structs.

Example

{:ok, subscription} = EventStore.subscribe(stream_uuid)

# receive first batch of events
receive do
  {:events, events} ->
    IO.puts "Received events: " <> inspect(events)
end
Link to this function subscribe_to_all_streams(subscription_name, subscriber, opts \\ []) View Source
subscribe_to_all_streams(String.t(), pid(), keyword()) ::
  {:ok, subscription :: pid()}
  | {:error, :subscription_already_exists}
  | {:error, reason :: term()}

Create a persistent subscription to all streams.

The subscriber process will be notified of each batch of events appended to any stream.

  • subscription_name is used to uniquely identify the subscription.

  • subscriber is a process that will be sent {:events, events} notification messages.

  • opts is an optional map providing additional subscription configuration:

    • start_from is a pointer to the first event to receive. It must be one of:

      • :origin for all events from the start of the stream (default).
      • :current for any new events appended to the stream after the subscription has been created.
      • any positive integer for an event id to receive events after that exact event.
    • selector to define a function to filter each event, i.e. returns only those elements for which fun returns a truthy value
    • mapper to define a function to map each recorded event before sending to the subscriber.

The subscription will resume from the last acknowledged event if it already exists. It will ignore the start_from argument in this case.

Returns {:ok, subscription} when subscription succeeds.

Example

{:ok, subscription} = EventStore.subscribe_to_all_streams("all_subscription", self())

# wait for the subscription confirmation
receive do
  {:subscribed, ^subscription} ->
    IO.puts "Successfully subscribed to all streams"
end

receive do
  {:events, events} ->
    IO.puts "Received events: " <> inspect(events)

    # acknowledge receipt
    EventStore.ack(subscription, events)
end
Link to this function subscribe_to_stream(stream_uuid, subscription_name, subscriber, opts \\ []) View Source
subscribe_to_stream(String.t(), String.t(), pid(), keyword()) ::
  {:ok, subscription :: pid()}
  | {:error, :subscription_already_exists}
  | {:error, reason :: term()}

Create a persistent subscription to a single stream.

The subscriber process will be notified of each batch of events appended to the single stream identified by stream_uuid.

  • stream_uuid is the stream to subscribe to. Use the $all identifier to subscribe to events from all streams.

  • subscription_name is used to uniquely identify the subscription.

  • subscriber is a process that will be sent {:events, events} notification messages.

  • opts is an optional map providing additional subscription configuration:

    • start_from is a pointer to the first event to receive. It must be one of:

      • :origin for all events from the start of the stream (default).
      • :current for any new events appended to the stream after the subscription has been created.
      • any positive integer for a stream version to receive events after.
    • selector to define a function to filter each event, i.e. returns only those elements for which fun returns a truthy value
    • mapper to define a function to map each recorded event before sending to the subscriber.

The subscription will resume from the last acknowledged event if it already exists. It will ignore the start_from argument in this case.

Returns {:ok, subscription} when subscription succeeds.

Notification messages

Subscribers will initially receive a {:subscribed, subscription} message once the subscription has successfully subscribed.

After this message events will be sent to the subscriber, in batches, as {:events, events} where events is a collection of EventStore.RecordedEvent structs.

Example

{:ok, subscription} = EventStore.subscribe_to_stream(stream_uuid, "example", self())

# wait for the subscription confirmation
receive do
  {:subscribed, ^subscription} ->
    IO.puts "Successfully subscribed to stream: " <> inspect(stream_uuid)
end

receive do
  {:events, events} ->
    IO.puts "Received events: " <> inspect(events)

    # acknowledge receipt
    EventStore.ack(subscription, events)
end
Link to this function unsubscribe_from_all_streams(subscription_name) View Source
unsubscribe_from_all_streams(String.t()) :: :ok

Unsubscribe an existing subscriber from all event notifications.

  • subscription_name is used to identify the existing subscription to remove.

Returns :ok on success.

Link to this function unsubscribe_from_stream(stream_uuid, subscription_name) View Source
unsubscribe_from_stream(String.t(), String.t()) :: :ok

Unsubscribe an existing subscriber from event notifications.

  • stream_uuid is the stream to unsubscribe from.

  • subscription_name is used to identify the existing subscription to remove.

Returns :ok on success.