Skip to content

Commit

Permalink
feat(#13): Add priority for tasks execution
Browse files Browse the repository at this point in the history
Closes #13.
  • Loading branch information
Alberdi committed Dec 19, 2023
1 parent d069f22 commit 21d5145
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 14 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ end).

In this case, the second task won't be executed and the call to `nhooks:do/3` will return `{stopped, {some, data}}`.

All tasks are registered with a default priority of `0` and then executed from lowest to highest priority. That priority can be passed as the last argument of `nhooks:registar_task/4`:

```erl

ok = nhooks:register_task(test_app, init, fun(Term) -> first, -1).
ok = nhooks:register_task(test_app, init, fun(Term) -> second end).
ok = nhooks:register_task(test_app, init, fun(Term) -> third end, 5).

```


## Support

Expand Down
31 changes: 17 additions & 14 deletions src/nhooks.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
-export([
do/3,
register_task/3,
register_task/4,
deregister_task/2,
deregister_app_tasks/1,
consult_tasks/2,
consult_app_tasks/1
]).

%%%% MACROS
-define(DEFAULT_PRIORITY, 0).
-define(PERSISTENT_TERM_KEY(AppName, Hook),
{nhooks, AppName, Hook}
).
Expand All @@ -38,11 +40,14 @@ do(AppName, Hook, Args) ->
Hooks = persistent_term:get(?PERSISTENT_TERM_KEY(AppName, Hook), []),
do(AppName, Hook, Hooks, Args).

register_task(AppName, Hook, Task) when is_function(Task) ->
do_register_task(AppName, Hook, Task);
register_task(AppName, Hook, {M, F} = Task) when is_atom(M), is_atom(F) ->
do_register_task(AppName, Hook, Task);
register_task(_AppName, _Hook, Other) ->
register_task(AppName, Hook, Task) ->
register_task(AppName, Hook, Task, ?DEFAULT_PRIORITY).

register_task(AppName, Hook, Task, Priority) when is_function(Task) ->
do_register_task(AppName, Hook, Task, Priority);
register_task(AppName, Hook, {M, F} = Task, Priority) when is_atom(M), is_atom(F) ->
do_register_task(AppName, Hook, Task, Priority);
register_task(_AppName, _Hook, Other, _Priority) ->
throw({badarg, Other}).

deregister_task(AppName, Hook) ->
Expand All @@ -65,7 +70,7 @@ consult_app_tasks(AppName) ->
%%%-----------------------------------------------------------------------------
do(_AppName, _Hook, [], _Args) ->
ok;
do(AppName, Hook, [Task | T], Args) ->
do(AppName, Hook, [{_Priority, Task} | T], Args) ->
try
case do_apply(Task, Args) of
stop -> stopped;
Expand All @@ -83,17 +88,15 @@ do_apply({Mod, Fun}, Args) ->
do_apply(Fun, Args) when is_function(Fun) ->
erlang:apply(Fun, Args).

do_register_task(AppName, Hook, Task) ->
do_register_task(AppName, Hook, Task, Priority) ->
Hooks = AppName:hooks(),
case lists:member(Hook, Hooks) of
true ->
ExistentTasks = persistent_term:get(
?PERSISTENT_TERM_KEY(AppName, Hook), []
),
persistent_term:put(
?PERSISTENT_TERM_KEY(AppName, Hook),
ExistentTasks ++ [Task]
);
Key = ?PERSISTENT_TERM_KEY(AppName, Hook),
ExistentTasks = persistent_term:get(Key, []),
NewTasks = ExistentTasks ++ [{Priority, Task}],
SortedTasks = lists:sort(fun({X,_}, {Y,_}) -> X =< Y end, NewTasks),
persistent_term:put(Key, SortedTasks);
false ->
erlang:error('non_existent_hook')
end.
Expand Down
20 changes: 20 additions & 0 deletions test/nhooks_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ all() ->
do_error_no_log,
do_until_stopped,
do_until_stopped_with_exceptions,
do_until_stopped_with_priority,
execution_of_one_fun_per_hook,
execution_of_one_mod_fun_per_hook,
execution_of_several_tasks_per_hook,
Expand Down Expand Up @@ -214,6 +215,25 @@ do_until_stopped_with_exceptions(_Conf) ->
3 = counters:get(Counter, 1),
ok.

do_until_stopped_with_priority() ->
[{userdata, [{doc, "Tests do until stopped with priority"}]}].

do_until_stopped_with_priority(_Conf) ->
Counter = counters:new(1, []),
ok = nhooks:register_task(?APP_NAME, init, fun(CounterRef) ->
counters:add(CounterRef, 1, 1)
end, 0),
ok = nhooks:register_task(?APP_NAME, init, fun(CounterRef) ->
counters:add(CounterRef, 1, 1),
{stop, {some, data}}
end, 5),
ok = nhooks:register_task(?APP_NAME, init, fun(CounterRef) ->
counters:add(CounterRef, 1, 1)
end, 3),
{stopped, {some, data}} = ?APP_NAME:init(Counter),
3 = counters:get(Counter, 1),
ok.

execution_of_one_fun_per_hook() ->
[
{userdata, [
Expand Down

0 comments on commit 21d5145

Please sign in to comment.