Task is an OTP abstraction for running concurrent jobs that begin work immediately and terminate when the computation finishes. Unlike a GenServer, a task does not serve requests over its lifetime; it performs a one-off operation or background job. section 10.0 section 10.1
Choose the task form according to how the result and process lifetime should be handled:
- Use Task.async/1 for an awaited task: it runs a zero-arity function in another process, returns immediately with a task struct, and sends the function result back to the caller. section 10.1.1
- Use Task.await/1 or Task.await/2 to receive the result; the default five-second timeout raises if the response does not arrive. section 10.1.1
- Use Task.start_link/1 for a non-awaited OTP-compliant job that sends no result message and terminates normally when its function finishes. section 10.1.2
- Use Task.Supervisor for dynamically started work whose lifetime must be independent from the request-handling or other process that initiated it. section 10.1.3
Parallel independent queries
Map independent queries to tasks, then await each task to collect the results. This replaces manual spawn, send, and receive code while allowing the computations to proceed concurrently: `1..5 |> Enum.map(&Task.async(fn -> run_query.("query #{&1}") end)) |> Enum.map(&Task.await/1)`. section 10.1.1
Supervised periodic metrics
A module can `use Task`, define `start_link/1` with `Task.start_link(&loop/0)`, and place the module under a supervisor. The loop periodically collects memory usage and process count without requiring a GenServer or an external scheduler. section 10.1.2
iex(2)> Task.Supervisor.start_child(
MyTaskSupervisor,
fn ->
IO.puts("Task started")
Process.sleep(2000)
IO.puts("Task stopping")
end
)
{:ok, #PID<0.118.0>} #1
Task started #2
Task stopping #3
Shows a dynamically supervised task starting, performing delayed work, and stopping independently. section 10.1.3
