Current section
Files
Jump to
Current section
Files
src/gaffer_hooks.erl
-module(gaffer_hooks).
-moduledoc "Hook behaviour for intercepting queue and job events.".
-doc "Hook event path.".
-type event() :: [atom()].
-doc "A hook callback function.".
-type hook_fun() :: fun((pre | post, event(), term()) -> term()).
-doc "A hook module or function.".
-type hook() :: module() | hook_fun().
-export_type([event/0]).
-export_type([hook_fun/0]).
-export_type([hook/0]).
-doc "Called before and after queue events.".
-callback gaffer_hook(pre | post, event(), term()) -> term().
% API
-export([with_hooks/4]).
-export([run_post_hooks/3]).
%--- API -----------------------------------------------------------------------
-doc false.
-spec with_hooks([hook()], event(), term(), fun((term()) -> term())) ->
dynamic().
with_hooks(QueueHooks, Event, Data, Fun) ->
case resolve(QueueHooks) of
[] ->
Fun(Data);
Hooks ->
Data1 = run_hooks(pre, Hooks, Event, Data),
Data2 = Fun(Data1),
run_hooks(post, Hooks, Event, Data2)
end.
-doc false.
-spec run_post_hooks([hook()], event(), term()) -> term().
run_post_hooks(QueueHooks, Event, Data) ->
run_hooks(post, resolve(QueueHooks), Event, Data).
%--- Internal ------------------------------------------------------------------
resolve(QueueHooks) ->
application:get_env(gaffer, hooks, []) ++ QueueHooks.
run_hooks(_Phase, [], _Event, Acc) ->
Acc;
run_hooks(Phase, [Hook | Rest], Event, Acc) ->
Acc1 =
try
call_hook(Hook, Phase, Event, Acc)
catch
Class:Reason:Stack ->
logger:warning(
~"Hook ~p crashed: ~p:~p~n~p",
[Hook, Class, Reason, Stack]
),
Acc
end,
run_hooks(Phase, Rest, Event, Acc1).
call_hook(Fun, Phase, Event, Data) when is_function(Fun, 3) ->
Fun(Phase, Event, Data);
call_hook(Mod, Phase, Event, Data) when is_atom(Mod) ->
Mod:gaffer_hook(Phase, Event, Data).