Hello everyone, I am having some issues understanding exits
and Task.await
From the elixir documentation about Task.await/2
If the timeout is exceeded, then the caller process will exit. If the task process is linked to the caller process which is the case when a task is started with
async
, then the task process will also exit.
It says “caller process will exit”, what does “exit” mean here? I think it means it will call Kernel.exit/1
function.
According to the documentation exit/1 will
Stops the execution of the calling process with the given reason
When I try to call exit from an iex session why does it not kill the current process, I expected it to kill the iex process but that’s not the case as seen here
Interactive Elixir (1.13.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> self()
#PID<0.111.0>
iex(2)> exit(:boom)
** (exit) :boom
iex(2)> self()
#PID<0.111.0>
Due to this when playing with Task.await on iex the caller process is not killed on exit so the task continues to run, check this sample code…
defmodule TaskTest do
def test_await() do
task_ref = Task.async(&perform/0)
return_value = Task.await(task_ref)
IO.puts "I am printed after await, task returned: #{inspect(return_value)}"
end
def perform(sleep_time \\ 10_000) do
IO.puts "Sleeping for #{sleep_time}ms zZz"
Process.sleep(sleep_time)
IO.puts "Done sleeping"
:return_value_for_caller
end
end
Now if I call TaskTest.test_await
in iex this is what I get
iex(3)> t = TaskTest.test_await
Sleeping for 10000ms zZz
** (exit) exited in: Task.await(%Task{owner: #PID<0.111.0>, pid: #PID<0.131.0>, ref: #Reference<0.979233406.103874576.149424>}, 5000)
** (EXIT) time out
(elixir 1.13.0) lib/task.ex:807: Task.await/2
iex:4: TaskTest.test_await/0
Done sleeping
As you can see the task is not exiting since the caller process(iex shell process) is not exiting on await timeout.
And it continues to run and prints Done sleeping
.
Now instead of the iex process if the caller process is different then it works as expected like…
iex(3)> {:ok, pid} = Task.start(&TaskTest.test_await/0)
Sleeping for 10000ms zZz
{:ok, #PID<0.133.0>}
iex(4)>
16:42:41.305 [error] Task #PID<0.133.0> started from #PID<0.111.0> terminating
** (stop) exited in: Task.await(%Task{owner: #PID<0.133.0>, pid: #PID<0.134.0>, ref: #Reference<0.979233406.103874575.148817>}, 5000)
** (EXIT) time out
(elixir 1.13.0) lib/task.ex:807: Task.await/2
iex:4: TaskTest.test_await/0
(elixir 1.13.0) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: &TaskTest.test_await/0
Args: []
nil
iex(5)> Process.alive?(pid)
false
Here the caller process is another task, when Task.await exceeds its timeout it exits the caller process(the task started with Task.start
) and hence the linked task also exits and never prints Done sleeping
.
I want to understand why the behaviour is different in iex? This leads to confusion when I am trying to play around with Task in iex. Is my understanding correct here?
Can someone help regarding this?