EventStore v0.17.0 EventStore View Source
EventStore is an 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 an existing persistent subscription to all streams.
Delete a previously recorded snapshop for a given source.
Delete an existing persistent subscription.
Link one or more existing events to another stream.
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
expected_version()
View Source
expected_version() ::
:any_version | :no_stream | :stream_exists | non_neg_integer()
expected_version() :: :any_version | :no_stream | :stream_exists | non_neg_integer()
start_from()
View Source
start_from() :: :origin | :current | non_neg_integer()
start_from() :: :origin | :current | non_neg_integer()
Link to this section Functions
ack(subscription, ack)
View Source
ack(
pid(),
EventStore.RecordedEvent.t()
| [EventStore.RecordedEvent.t()]
| non_neg_integer()
) :: :ok | {:error, reason :: term()}
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 RecordedEvent
s, or the event number of
the recorded event to acknowledge.
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_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
.
configuration() View Source
Get the event store configuration for the environment.
delete_all_streams_subscription(subscription_name) View Source
Delete an existing persistent subscription to all streams.
stream_uuid
is the stream the subscription is subscribed to.subscription_name
is used to identify the existing subscription to remove.
Returns :ok
on success.
delete_snapshot(source_uuid) View Source
Delete a previously recorded snapshop for a given source.
Returns :ok
on success, or when the snapshot does not exist.
delete_subscription(stream_uuid, subscription_name) View Source
Delete an existing persistent subscription.
stream_uuid
is the stream the subscription is subscribed to.subscription_name
is used to identify the existing subscription to remove.
Returns :ok
on success.
link_to_stream(stream_uuid, expected_version, events_or_event_ids, timeout \\ 15000)
View Source
link_to_stream(
String.t(),
expected_version(),
[EventStore.RecordedEvent.t()] | [non_neg_integer()],
timeout() | nil
) ::
:ok
| {:error, :cannot_append_to_all_stream}
| {:error, :stream_exists}
| {:error, :stream_does_not_exist}
| {:error, :wrong_expected_version}
| {:error, reason :: term()}
link_to_stream( String.t(), expected_version(), [EventStore.RecordedEvent.t()] | [non_neg_integer()], timeout() | nil ) :: :ok | {:error, :cannot_append_to_all_stream} | {:error, :stream_exists} | {:error, :stream_does_not_exist} | {:error, :wrong_expected_version} | {:error, reason :: term()}
Link one or more existing events to another stream.
Allows you to construct streams containing events already appended to any other stream. This is more efficient than copying events between streams since only a reference to the existing event is created.
stream_uuid
is used to uniquely identify the target 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_or_event_ids
is a list of%EventStore.EventData{}
structs or event ids.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
.
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()}
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.
read_snapshot(source_uuid)
View Source
read_snapshot(String.t()) ::
{:ok, EventStore.Snapshots.SnapshotData.t()} | {:error, :snapshot_not_found}
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.
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()}
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.
record_snapshot(snapshot)
View Source
record_snapshot(EventStore.Snapshots.SnapshotData.t()) ::
:ok | {:error, reason :: term()}
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.
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.
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()}
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.
subscribe(stream_uuid, opts \\ [])
View Source
subscribe(String.t(),
selector: (EventStore.RecordedEvent.t() -> any()),
mapper: (EventStore.RecordedEvent.t() -> any())
) :: :ok | {:error, term()}
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 valuemapper
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
subscribe_to_all_streams(subscription_name, subscriber, opts \\ []) View Source
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 valuemapper
to define a function to map each recorded event before sending to the subscriber.concurrency_limit
defines the maximum number of concurrent subscribers allowed to connect to the subscription. By default only one subscriber may connect. If too many subscribers attempt to connect to the subscription an{:error, :too_many_subscribers}
is returned.
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
subscribe_to_stream(stream_uuid, subscription_name, subscriber, opts \\ []) View Source
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.concurrency_limit
defines the maximum number of concurrent subscribers allowed to connect to the subscription. By default only one subscriber may connect. If too many subscribers attempt to connect to the subscription an{:error, :too_many_subscribers}
is returned.buffer_size
limits how many in-flight events will be sent to the subscriber process before acknowledgement of successful processing. This limits the number of messages sent to the subscriber and stops their message queue from getting filled with events. Defaults to one in-flight event.partition_by
is an optional function used to partition events to subscribers. It can be used to guarantee processing order when multiple subscribers have subscribed to a single subscription. The function is passed a single argument (anEventStore.RecordedEvent
struct) and must return the partition key. As an example to guarantee events for a single stream are processed serially, but different streams are processed concurrently, you could use thestream_uuid
as the partition key.alias EventStore.RecordedEvent
by_stream = fn %RecordedEvent{stream_uuid: stream_uuid} -> stream_uuid end
{:ok, _subscription} =
EventStore.subscribe_to_stream(stream_uuid, "example", self(), concurrency_limit: 10, partition_by: by_stream )
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
unsubscribe_from_all_streams(subscription_name)
View Source
unsubscribe_from_all_streams(String.t()) :: :ok
unsubscribe_from_all_streams(String.t()) :: :ok
Unsubscribe an existing subscriber from all event notifications.
subscription_name
is used to identify the existing subscription process to stop.
Returns :ok
on success.
unsubscribe_from_stream(stream_uuid, subscription_name) View Source
Unsubscribe an existing subscriber from event notifications.
stream_uuid
is the stream to unsubscribe from.subscription_name
is used to identify the existing subscription process to stop.
Returns :ok
on success.