Lightweight task manager, allowing retries, callbacks, assurance that the task succeeded, and more…
def deps do
[
{:tarearbol, "~> 1.12"}
]
end
Add :tarearbol
to the list of applications and you are all set.
Tarearbol.ensure fn ->
unless Enum.random(1..100) == 42, do: raise "Incorrect answer"
{:ok, 42}
end
# some bad-case logging
{:ok, 42}
res = 1..20
|> Enum.map(fn i ->
fn -> Process.sleep(Enum.random(1..i)); i end
end)
|> Tarearbol.Job.ensure_all(attempts: 1)
[{:ok, 1}, {:ok, 2}, ..., {:ok, 20}]
Tarearbol.ensure fn ->
raise "Incorrect answer"
end, attempts: 10
# some bad-case logging
{:error,
%{job: #Function<20.87737649/0 in :erl_eval.expr/5>,
outcome: {%RuntimeError{message: "Incorrect answer"},
[{:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 668]},
{Task.Supervised, :do_apply, 2,
[file: 'lib/task/supervised.ex', line: 85]},
{Task.Supervised, :reply, 5, [file: 'lib/task/supervised.ex', line: 36]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}}}
Tarearbol.ensure fn ->
unless Enum.random(1..100) == 42, do: raise "Incorrect answer"
{:ok, 42}
end, delay: 1000
# some slow bad-case logging
{:ok, 42}
Tarearbol.ensure fn ->
unless Enum.random(1..100) == 42, do: raise "Incorrect answer"
{:ok, 42}
end, on_success: fn data -> IO.inspect(data, label: "★") end,
on_retry: fn data -> IO.inspect(data, label: "☆") end
# some slow bad-case logging
# ⇓⇓⇓⇓ one or more of ⇓⇓⇓⇓
☆: %{cause: :on_raise,
data: {%RuntimeError{message: "Incorrect answer"},
[{:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 670]},
{:erl_eval, :exprs, 5, [file: 'erl_eval.erl', line: 122]},
{Task.Supervised, :do_apply, 2, [file: 'lib/task/supervised.ex', line: 85]},
{Task.Supervised, :reply, 5, [file: 'lib/task/supervised.ex', line: 36]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}}
# ⇑⇑⇑⇑ one or more of ⇑⇑⇑⇑
★: 42
{:ok, 42}
attempts
integer, an amount of attempts before giving up,0
for forever; default::infinity
delay
the delay between attempts, default::none
; -raise
: whentrue
, will raise after all attempts were unsuccessful, or return{:error, outcome}
tuple otherwise, default:false
;accept_not_ok
: whentrue
, any result save for{:error, _}
will be accepted as correct, otherwise only{:ok, _}
is treated as correct, default:true
;on_success
: callback when the task returned a result, default:nil
;on_retry
: callback when the task failed and scheduled for retry, default::debug
;on_fail
: callback when the task completely failed, default::warn
.
for :attempts
and :delay
keys one might specify the following values:
integer
→ amount to be used as is (milliseconds fordelay
, number for attempts);float
→ amount of thousands, rounded (seconds fordelay
, thousands for attempts);:none
→0
;:tiny
→10
;:medium
→100
;:infinity
→-1
,:attempts
only.
Tarearbol.run_in fn -> IO.puts(42) end, 1_000 # 1 sec
Tarearbol.spawn fn -> IO.puts(42) end # immediately
Tarearbol.run_in fn -> IO.inspect(42) end, 1_000 # 1 sec
Tarearbol.run_in fn -> IO.inspect(:foo) end, 1_000 # 1 sec
Tarearbol.drain
42 # immediately, from `IO.inspect`
:foo # immediately, from `IO.inspect`
[ok: 42, ok: :foo] # immediately, the returned value(s)
1.12.0
decoupled from:formulae
dependency, removedCrontab
1.11.2
defaults: [instant_perform?: integer()]
to runperform/2
in given number of msecs after start1.11.0
defaults: [instant_perform?: true]
to instantly runperform/2
upon start1.10.3
OTP27 ready + offloading state in cluster when node goes down1.10.1
OTP26 ready1.10.0
single global state process in cluster +put_new/3
to avoid flip-flopping children in cluster1.8.0
finally standardized and deprecated multi in favor of normalput/3
/get/2
/del/3
1.7.0
less aggressiveMap.update!/3
+ modern era update1.6.0
HashRing
default forsynch
/asynch
calls inTarearbol.DynamicWorker
selection (to preserve idempotency amongst calls)1.5.0
defaults forpayload
,timeout
andlull
accepted inuse DynamicManager
options asdefaults: …
1.4.4
DynamicManager
accepts{:payload, payload}
message to update a payload1.4.3
accept function heads withdefsynch/1
anddefasynch/1
1.4.1
random pool worker by default, pass:stream
, or override__free_worker__
if needed1.4.0
Tarearbol.Pool
to easily create worker pools on top ofTarearbol.DynamicManager
cast/2
,call/3
,terminate/2
callbacks for workers to initiale message passing from outsideinit:
argument in call touse Tarearbol.DynamicManager
to allow custom payload initialization (routed tohandle_continue/2
of underlying process)
1.3.0
standardized types, better docs;1.2.1
cast/2
and standard replies from worker (:halt | :replace | :ok | any()};1.2.0
call/3
andterminate/2
callbacks inDynamicManager
,0
timeout forperform/2
;1.1.2
transparent support forEcto
retries;1.0.0
deprecated local functions inrun_in
/run_at
in favor ofTarearbol.Scheduler
;0.6.0
code format, explicitTask.shutdown
;0.5.0
usingDETS
to storerun_at
jobs;0.4.2
Tarearbol.spawn_ensured/2
;0.4.1
run_at
now repeats itself properly;0.4.0
allowrun_at
recurrent tasks.