Chronicle.Events.ConcurrencyScope (cratis_chronicle v3.16.1)

Copy Markdown View Source

Represents a concurrency scope for Chronicle append operations.

Concurrency scopes let you assert the expected tail sequence number before appending one or more events. You can optionally narrow the check to the current event source, stream, source type, and event types.

alias Chronicle.Events.ConcurrencyScope

scope =
  ConcurrencyScope.for_event_source(3,
    event_types: [MyApp.Events.FundsDeposited, MyApp.Events.FundsWithdrawn]
  )

:ok = Chronicle.append_many("account-42", [...], concurrency_scope: scope)

The event_source_id option is a boolean because the actual event source id comes from the Chronicle.append/3 or Chronicle.append_many/3 call.

Summary

Functions

Reads the current tail sequence number for event_source_id - narrowed the same way the returned scope narrows, via :event_stream_type, :event_stream_id, :event_source_type and :event_types - and returns a scope expecting that tail. A live-read shortcut for for_event_source(tail, opts), mirroring .NET's ConcurrencyScopeBuilder combined with a tail read (the pattern the optimistic strategy itself follows).

Creates a scope asserting that no event matches the scope's dimensions yet - the guard for creation-only operations ("this event source must not have been registered already").

Creates a concurrency scope that includes the current append event source id.

Creates a new concurrency scope.

Returns the sentinel scope representing no explicit concurrency constraint.

Includes the current append's event source id in the scope. Mirrors .NET's ConcurrencyScopeBuilder.WithEventSourceId().

Narrows the scope to a specific event source type. Mirrors .NET's ConcurrencyScopeBuilder.WithEventSourceType().

Narrows the scope to a specific event stream id. Mirrors .NET's ConcurrencyScopeBuilder.WithEventStreamId().

Narrows the scope to a specific event stream type. Mirrors .NET's ConcurrencyScopeBuilder.WithEventStreamType().

Adds a single event type to the scope's narrowing. Mirrors .NET's ConcurrencyScopeBuilder.WithEventType().

Adds a list of event types to the scope's narrowing. Mirrors .NET's repeated ConcurrencyScopeBuilder.WithEventType() calls.

Sets the expected sequence number on a scope. Pipe-able continuation of new/2, for_event_source/2, or any other scope - mirrors .NET's ConcurrencyScopeBuilder.WithSequenceNumber().

Types

event_type_module()

@type event_type_module() :: module()

option()

@type option() ::
  {:event_source_id, boolean()}
  | {:event_stream_type, String.t() | atom() | nil}
  | {:event_stream_id, String.t() | atom() | nil}
  | {:event_source_type, String.t() | atom() | nil}
  | {:event_types, [event_type_module()] | nil}
  | {:expects_no_matching_event, boolean()}

t()

@type t() :: %Chronicle.Events.ConcurrencyScope{
  event_source_id: boolean(),
  event_source_type: String.t(),
  event_stream_id: String.t(),
  event_stream_type: String.t(),
  event_types: [event_type_module()],
  expects_no_matching_event: boolean(),
  sequence_number: non_neg_integer()
}

Functions

at_tail(event_source_id, opts \\ [])

@spec at_tail(String.t(), keyword()) :: {:ok, t()} | {:error, term()}

Reads the current tail sequence number for event_source_id - narrowed the same way the returned scope narrows, via :event_stream_type, :event_stream_id, :event_source_type and :event_types - and returns a scope expecting that tail. A live-read shortcut for for_event_source(tail, opts), mirroring .NET's ConcurrencyScopeBuilder combined with a tail read (the pattern the optimistic strategy itself follows).

{:ok, scope} = ConcurrencyScope.at_tail("account-1", event_stream_type: "Transactions")
Chronicle.append("account-1", %FundsDeposited{amount: 10}, concurrency_scope: scope)

Accepts :client, :namespace and :event_sequence_id in addition to the narrowing options above. Returns {:error, reason} when the tail read itself fails.

expecting_no_matching_event(opts \\ [])

@spec expecting_no_matching_event([option()] | t()) :: t()

Creates a scope asserting that no event matches the scope's dimensions yet - the guard for creation-only operations ("this event source must not have been registered already").

Mirrors .NET's ConcurrencyScopeBuilder.ExpectingNoMatchingEvent(). It sends the kernel's explicit no-matching-event condition; leaving the sequence number unset is not a substitute, because that disables the check instead of asserting anything. The narrowing options are those of new/2 - typically the event source and the event types that would make the append invalid:

scope =
  ConcurrencyScope.expecting_no_matching_event(
    event_source_id: true,
    event_types: [MyApp.Events.UserRegistered]
  )

Chronicle.append("user-1", %UserRegistered{}, concurrency_scope: scope)

for_event_source(sequence_number, opts \\ [])

@spec for_event_source(non_neg_integer(), [option()]) :: t()

Creates a concurrency scope that includes the current append event source id.

new(sequence_number, opts \\ [])

@spec new(non_neg_integer(), [option()]) :: t()

Creates a new concurrency scope.

none()

@spec none() :: t()

Returns the sentinel scope representing no explicit concurrency constraint.

with_event_source(scope)

@spec with_event_source(t()) :: t()

Includes the current append's event source id in the scope. Mirrors .NET's ConcurrencyScopeBuilder.WithEventSourceId().

with_event_source_type(scope, event_source_type)

@spec with_event_source_type(t(), String.t() | atom()) :: t()

Narrows the scope to a specific event source type. Mirrors .NET's ConcurrencyScopeBuilder.WithEventSourceType().

with_event_stream_id(scope, event_stream_id)

@spec with_event_stream_id(t(), String.t() | atom()) :: t()

Narrows the scope to a specific event stream id. Mirrors .NET's ConcurrencyScopeBuilder.WithEventStreamId().

with_event_stream_type(scope, event_stream_type)

@spec with_event_stream_type(t(), String.t() | atom()) :: t()

Narrows the scope to a specific event stream type. Mirrors .NET's ConcurrencyScopeBuilder.WithEventStreamType().

with_event_type(scope, event_type)

@spec with_event_type(t(), event_type_module()) :: t()

Adds a single event type to the scope's narrowing. Mirrors .NET's ConcurrencyScopeBuilder.WithEventType().

with_event_types(scope, event_types)

@spec with_event_types(t(), [event_type_module()]) :: t()

Adds a list of event types to the scope's narrowing. Mirrors .NET's repeated ConcurrencyScopeBuilder.WithEventType() calls.

with_sequence_number(scope, sequence_number)

@spec with_sequence_number(t(), non_neg_integer()) :: t()

Sets the expected sequence number on a scope. Pipe-able continuation of new/2, for_event_source/2, or any other scope - mirrors .NET's ConcurrencyScopeBuilder.WithSequenceNumber().