evoq_decision_runtime (evoq v1.19.0)

View Source

Runtime for the evoq_decision behaviour.

Wires the user-facing callback contract (context/1, decide/2) to the event-store adapter's conditional-append primitive (append_if_no_tag_matches/4):

1. Call Mod:context(Command) to get the tag-filter. 2. Read the context events matching that filter (DCB-stream only). 3. Compute the seq cutoff from the highest version seen (or -1 for "saw nothing"). 4. Call Mod:decide(ContextEvents, Command). 5. Conditionally append the resulting events. 6. On {error, {context_changed, _}}, sleep with bounded exponential backoff + jitter, then retry from step 2. Retries are bounded by Mod:retry_budget/0 (default 3).

Returns: - {ok, [Event]}: events appended; commit produced. - {error, retry_budget_exhausted}: too many context_changed conflicts. Caller decides whether to escalate or give up. - {error, Reason}: domain error from decide/2 or backend error from the append path. Propagated as-is.

Summary

Functions

Public-for-testing version of the per-event filter predicate. Accepts either an event map (using maps:get(tags, ...)) or a raw tag list — handy for property-based tests that don't want to build full event maps. Subject to change without semver guarantees.

Functions

collect_tags(_)

dispatch(Mod, StoreId, Command)

-spec dispatch(module(), StoreId :: atom(), Command :: map()) ->
                  {ok, [map()]} | {error, retry_budget_exhausted} | {error, term()}.

match_filter(Tags, Filter)

-spec match_filter(Event | Tags, evoq_decision:context_filter()) -> boolean()
                      when Event :: map(), Tags :: [binary()].

Public-for-testing version of the per-event filter predicate. Accepts either an event map (using maps:get(tags, ...)) or a raw tag list — handy for property-based tests that don't want to build full event maps. Subject to change without semver guarantees.