Task (Elixir)

Elixir Tasks

Creating Tasks

Tasks can be started either with an anonymous function or using the Module-Function-Arguments (MFA) form.

Handling Timeouts with receive

A plain receive waits forever if no matching message arrives.

Use an after clause to avoid blocking indefinitely (this is basically a timeout in Erlang).

receive do
  {^pid, :result, value} ->
    value
after
  2000 ->
    raise "Timed out!"
end
  • Prevents hanging when a process crashes or takes too long.
  • Timeout is specified in milliseconds.

Task.await/2

  • Default timeout: 5 seconds
  • Raises an exception if the task doesn't finish in time.
Task.await(task)
# default: 5000 ms

Task.await(task, 7000)
# custom timeout

Task.await(task, :infinity)
# wait forever

Task.yield/2

Unlike `Task.await`, `Task.yield` lets you poll a task without crashing on timeout.

Returns:

  • `{:ok, result}` → task completed
  • `nil` → timeout expired
case Task.yield(task, 5000) do
  {:ok, result} ->
    result

  nil ->
    Logger.warn("Timed out!")
    Task.shutdown(task)
end

Useful for:

  • Long-running background work.
  • Periodically checking task completion.
  • Gracefully shutting down stalled tasks.

Task.shutdown/1

Stops a running task.

  • Returns `{:ok, result}` if the task finishes while shutting down.
  • Returns `nil` if it doesn't.

Often used together with `Task.yield`.

Human-Friendly Time Values

Instead of hardcoding milliseconds, use Erlang's :timer helpers.

:timer.seconds(5)   ;; 5000
:timer.minutes(5)   ;; 300000
:timer.hours(5)     ;; 18000000

Task.await(task, :timer.seconds(7))

This makes timeout values easier to read and maintain.

References: