Skip to content

Instantly share code, notes, and snippets.

@arkgil
Created October 9, 2018 10:34
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arkgil/16504695e64d0fd504e1a110f672d660 to your computer and use it in GitHub Desktop.
Save arkgil/16504695e64d0fd504e1a110f672d660 to your computer and use it in GitHub Desktop.
-module(task).
-export([async/1, async/3]).
-export([await/1, await/2, await/3]).
-opaque t() :: #{tpid := pid(), tref := reference()}.
-type await_opts() :: [kill].
-export_type([t/0]).
-export_type([await_opts/0]).
-define(DEFAULT_AWAIT_TIMEOUT, 5000).
-define(DEFAULT_AWAIT_OPTS, []).
%%-------------------------------------------------------------------
%% API
%%-------------------------------------------------------------------
-spec async(fun(() -> any())) -> t().
async(Fun) when is_function(Fun, 0) ->
async(erlang, apply, [Fun, []]).
-spec async(module(), Fun :: atom(), Args :: list()) -> t().
async(Mod, Fun, Args) when is_atom(Mod), is_atom(Fun), is_list(Args) ->
TPid = spawn(fun task_init/0),
TRef = make_ref(),
TPid ! {call, self(),TRef, Mod, Fun, Args},
#{tpid => TPid, tref => TRef}.
-spec await(t()) -> {ok, Result :: term()} | {error, timeout | term()}.
await(Task) ->
await(Task, ?DEFAULT_AWAIT_TIMEOUT).
-spec await(t(), timeout()) -> {ok, Result :: term()} | {error, timeout | term()}.
await(Task, Timeout) ->
await(Task, Timeout, ?DEFAULT_AWAIT_OPTS).
-spec await(t(), timeout(), await_opts()) -> {ok, Result :: term()} | {error, timeout | term()}.
await(#{tpid := TPid, tref := TRef}, Timeout, Opts) ->
MRef = monitor(process, TPid),
receive
{TRef, Result} ->
demonitor(MRef, [flush]),
{ok, Result};
{'DOWN', MRef, process, TPid, Reason} ->
{error, Reason}
after
Timeout ->
demonitor(MRef, [flush]),
case proplists:get_bool(kill, Opts) of
true ->
exit(TPid, kill);
false ->
ok
end,
{error, timeout}
end.
%%-------------------------------------------------------------------
%% Helpers
%%-------------------------------------------------------------------
task_init() ->
receive
{call, Owner, TRef, Mod, Fun, Args} ->
Result = apply(Mod, Fun, Args),
Owner ! {TRef, Result}
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment