Packages
tarearbol
1.4.4
1.12.0
1.11.2
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.0
1.9.102
1.9.101
1.9.100
1.9.99
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.2
1.8.1
1.8.0
1.7.0
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.0
0.99.11
0.99.10
0.99.9
0.99.8
0.99.7
0.99.6
0.99.4
0.99.3
0.99.2
0.99.1
0.99.0
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.0
0.9.6
0.9.5
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
The supervised tree of tasks, simplifying the process of handling: - recurrent tasks - retried tasks - long tasks - etc
Current section
Files
Jump to
Current section
Files
README.md
# Tarearbol [](https://kantox.com/)  
**Lightweight task manager, allowing retries, callbacks, assurance that the task succeeded, and more…**
## Installation
```elixir
def deps do
[
{:tarearbol, "~> 1.2"}
]
end
```
## Features
### Task supervision tree for granted
Add `:tarearbol` to the list of applications and you are all set.
### Infinite retries
```elixir
Tarearbol.ensure fn ->
unless Enum.random(1..100) == 42, do: raise "Incorrect answer"
{:ok, 42}
end
# some bad-case logging
{:ok, 42}
```
### Async execution of many tasks with retries
```elixir
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}]
```
### Limited amount of retries
```elixir
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]}]}}}
```
### Delay between retries
```elixir
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}
```
### Callbacks
```elixir
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}
```
### Allowed options
- `attempts` integer, an amount of attempts before giving up, `0` for forever; default: `:infinity`
- `delay` the delay between attempts, default: `:none`;
- `raise`: when `true`, will raise after all attempts were unsuccessful, or return `{:error, outcome}` tuple otherwise, default: `false`;
- `accept_not_ok`: when `true`, 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 for `delay`, number for attempts);
- `float` → amount of thousands, rounded (seconds for `delay`, thousands for attempts);
- `:none` → `0`;
- `:tiny` → `10`;
- `:medium` → `100`;
- `:infinity` → `-1`, `:attempts` only.
### Task spawning
```elixir
Tarearbol.run_in fn -> IO.puts(42) end, 1_000 # 1 sec
Tarearbol.spawn fn -> IO.puts(42) end # immediately
```
### Task draining
```elixir
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)
```
### [Dynamic Workers Management](https://hexdocs.pm/tarearbol/dynamic_workers_management.html)
### Changelog
- **`1.4.4`** `DynamicManager` accepts `{:payload, payload}` message to update a payload
- **`1.4.3`** accept function heads with `defsynch/1` and `defasynch/1`
- **`1.4.1`** random pool worker by default, pass `:stream`, or override `__free_worker__` if needed
- **`1.4.0`**
- **`Tarearbol.Pool`** to easily create worker pools on top of `Tarearbol.DynamicManager`
- **`cast/2`, `call/3`, `terminate/2`** callbacks for workers to initiale message passing from outside
- **`init:`** argument in call to `use Tarearbol.DynamicManager` to allow custom payload initialization (routed to `handle_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` and `terminate/2` callbacks in `DynamicManager`, `0` timeout for `perform/2`;
- **`1.1.2`** transparent support for `Ecto` retries;
- **`1.0.0`** deprecated local functions in `run_in`/`run_at` in favor of `Tarearbol.Scheduler`;
- **`0.6.0`** code format, explicit `Task.shutdown`;
- **`0.5.0`** using `DETS` to store `run_at` jobs;
- **`0.4.2`** `Tarearbol.spawn_ensured/2`;
- **`0.4.1`** `run_at` now repeats itself properly;
- **`0.4.0`** allow `run_at` recurrent tasks.
### [Documentation](https://hexdocs.pm/tarearbol)