Run all functions concurrently and collect every result, regardless of failures.
When to use
- Running a batch of independent jobs where partial failure is acceptable and you need to know which succeeded — e.g., sending notifications to multiple channels.
- Executing health checks or non-critical side effects in parallel and inspecting each outcome individually.
How it works
All functions are spawned concurrently as monitored processes. The caller
waits for every task to complete. Results are collected into an Erlang
:array indexed by input position, so the output order always matches
the input order regardless of completion order. Each slot is
{:ok, value} or {:error, reason}. Tasks exceeding the timeout receive
{:error, :timeout}.
Algorithm Complexity
| Time | Space |
|---|---|
| O(n) spawns + O(n) result collection | O(n) — :array of results + monitored processes |
Examples
iex> Resiliency.AllSettled.run([fn -> 1 end, fn -> 2 end])
[{:ok, 1}, {:ok, 2}]
iex> Resiliency.AllSettled.run([])
[]Mixed successes and failures:
iex> [{:ok, 1}, {:error, {%RuntimeError{message: "boom"}, _}}, {:ok, 3}] =
...> Resiliency.AllSettled.run([
...> fn -> 1 end,
...> fn -> raise "boom" end,
...> fn -> 3 end
...> ])With a timeout — completed tasks return their results, timed-out tasks
get {:error, :timeout}:
Resiliency.AllSettled.run([
fn -> quick_work() end,
fn -> slow_work() end
], timeout: 1_000)
# => [{:ok, result}, {:error, :timeout}]Telemetry
All events are emitted in the caller's process via :telemetry.span/3. See
Resiliency.Telemetry for the complete event catalogue.
[:resiliency, :all_settled, :run, :start]
Emitted before tasks are spawned.
Measurements
| Key | Type | Description |
|---|---|---|
system_time | integer | System.system_time() at emission time |
Metadata
| Key | Type | Description |
|---|---|---|
count | integer | Number of functions submitted |
[:resiliency, :all_settled, :run, :stop]
Emitted after all tasks complete (or timeout).
Measurements
| Key | Type | Description |
|---|---|---|
duration | integer | Elapsed native time units (System.monotonic_time/0 delta) |
Metadata
| Key | Type | Description |
|---|---|---|
count | integer | Total number of tasks |
ok_count | integer | Number of tasks that returned {:ok, _} |
error_count | integer | Number of tasks that returned {:error, _} |
[:resiliency, :all_settled, :run, :exception]
Emitted if run/2 raises or exits unexpectedly.
Measurements
| Key | Type | Description |
|---|---|---|
duration | integer | Elapsed native time units |
Metadata
| Key | Type | Description |
|---|---|---|
count | integer | Number of functions submitted |
kind | atom | Exception kind (:error, :exit, or :throw) |
reason | term | The exception or exit reason |
stacktrace | list | Stack at the point of the exception |
Summary
Functions
Run all functions concurrently. Wait for all to complete and return results in input order.
Types
@type task_fun() :: (-> any())
Functions
Run all functions concurrently. Wait for all to complete and return results in input order.
Unlike Task.await_many/2, this never crashes the caller. Each result is
{:ok, value} or {:error, reason}. Results are always in the same order
as the input list, regardless of which tasks finish first. Tasks that exceed
the timeout get {:error, :timeout}.
Returns [] for an empty list.
Parameters
funs-- a list of zero-arity functions to execute concurrently.opts-- keyword list of options. Defaults to[].:timeout-- milliseconds or:infinity. Defaults to:infinity.
Returns
A list of {:ok, value} or {:error, reason} tuples in the same order as the input list. Tasks that exceed the timeout produce {:error, :timeout}. An empty input list returns [].
Examples
iex> Resiliency.AllSettled.run([fn -> 1 end, fn -> 2 end])
[{:ok, 1}, {:ok, 2}]
iex> Resiliency.AllSettled.run([])
[]