evoq_decision behaviour (evoq v1.23.0)
View SourceDCB Decision behaviour (Dynamic Consistency Boundary).
A Decision is a write-side construct that sits alongside the aggregate. Where an aggregate locks on its own stream's version, a Decision locks on the absence of new events matching a tag-filter context query. Decisions are for cross-cutting checks that don't fit the per-entity Dossier shape: uniqueness, allocation against shared resources, idempotency keys, rate limits.
Callbacks
Required: context(Command :: map()) -> context_filter() Describe the tag-filter context this decision queries. The runtime reads matching events, then passes them to decide/2.
decide(ContextEvents :: [map()], Command :: map()) -> {ok, [Event :: map()]} | {error, Reason :: term()} Pure decision function. Given the current context and the command, return the events to append OR an error. The runtime appends conditionally via the configured event-store adapter.
Optional: retry_budget() -> non_neg_integer() Maximum retries on context_changed conflicts. Default 3.
CCC payload conditions
The context query can scope on opaque event-data fields, not just tags/types: {payload_match, Key, Value} and {payload_hash_match, Keys, Values}. The store must declare the matching payload index; otherwise the decision fails loudly with {error, {payload_index_unavailable, Filter}}. See the context_filter() type docs.
limitations
- The runtime considers only events from the DCB pseudo-stream (the binary "_dcb"). Mixed-mode use cases (aggregate streams + DCB sharing tags) are not supported; use evoq_aggregate if the consistency boundary is per-aggregate, evoq_decision if it's cross-cutting via DCB.
Summary
Types
-type context_filter() :: {any_of, [binary()]} | {all_of, [binary()]} | {event_type, binary()} | {payload_match, Key :: binary(), Value :: binary()} | {payload_hash_match, Keys :: [binary()], Values :: [binary()]} | {and_, [context_filter()]} | {or_, [context_filter()]}.
Callbacks
-callback context(Command :: map()) -> context_filter().
-callback init_decision_model() -> Model :: term().
-callback retry_budget() -> non_neg_integer().