Current section
Files
Jump to
Current section
Files
src/evoq_failure_context.erl
%% @doc Failure context for tracking retry state.
%%
%% Maintains state across retry attempts for event handlers.
%% Used to implement sophisticated retry strategies with
%% exponential backoff, jitter, and dead letter handling.
%%
%% @author rgfaber
-module(evoq_failure_context).
-include("evoq.hrl").
%% API
-export([new/3]).
-export([increment/1]).
-export([get_attempt/1, get_error/1, get_event/1]).
-export([get_handler/1, get_duration/1]).
-export([with_stacktrace/2]).
%%====================================================================
%% API
%%====================================================================
%% @doc Create a new failure context.
-spec new(atom(), map(), term()) -> #evoq_failure_context{}.
new(HandlerModule, Event, Error) ->
Now = erlang:system_time(millisecond),
#evoq_failure_context{
handler_module = HandlerModule,
event = Event,
error = Error,
attempt_number = 1,
first_failure_at = Now,
last_failure_at = Now,
stacktrace = []
}.
%% @doc Increment the attempt counter and update timestamp.
-spec increment(#evoq_failure_context{}) -> #evoq_failure_context{}.
increment(#evoq_failure_context{attempt_number = N} = Context) ->
Context#evoq_failure_context{
attempt_number = N + 1,
last_failure_at = erlang:system_time(millisecond)
}.
%% @doc Get the current attempt number.
-spec get_attempt(#evoq_failure_context{}) -> pos_integer().
get_attempt(#evoq_failure_context{attempt_number = N}) -> N.
%% @doc Get the error that caused the failure.
-spec get_error(#evoq_failure_context{}) -> term().
get_error(#evoq_failure_context{error = Error}) -> Error.
%% @doc Get the event that failed.
-spec get_event(#evoq_failure_context{}) -> map().
get_event(#evoq_failure_context{event = Event}) -> Event.
%% @doc Get the handler module.
-spec get_handler(#evoq_failure_context{}) -> atom().
get_handler(#evoq_failure_context{handler_module = Handler}) -> Handler.
%% @doc Get the duration since first failure.
-spec get_duration(#evoq_failure_context{}) -> non_neg_integer().
get_duration(#evoq_failure_context{first_failure_at = First, last_failure_at = Last}) ->
Last - First.
%% @doc Add stacktrace to the context.
-spec with_stacktrace(list(), #evoq_failure_context{}) -> #evoq_failure_context{}.
with_stacktrace(Stacktrace, Context) ->
Context#evoq_failure_context{stacktrace = Stacktrace}.