Why does Task.await not stop the awaited process on timeout?

Hey, this might be kind of a noob question - but I always was under the assumption that the process which is awaited by Task.await would die as soon as the timeout is reached. Given the following code:

defmodule Greeter do
  def run do
    task = Task.async(&greeter/0)
    Task.await(task, 10_000)
    IO.puts("work is done")
  end

  defp greeter do
    Process.sleep(1000)
    IO.puts("Hello")
    greeter()
  end
end

If I run this in iex I would expect it to stop printing “Hello” to the shell after 10 seconds timed out. Instead I’m getting the error that the timeout has been reached but the greeter would still print “Hello” every second to the console. What am I missing here?

This is because iex master process is trapping exits, which means it doesn’t just crash when a linked process crashes. Instead, it receives a message, that is handled in form of error being printed to the user.

Your code will work as you’d expect if you didn’t start it from iex. Even in iex you can spawn an intermediary process to observe the behavior as you’d expect:

iex(2)> defmodule Greeter do                                                                                                                                              
...(2)>   def run do
...(2)>     task = Task.async(&greeter/0)
...(2)>     Task.await(task, 10_000)
...(2)>     IO.puts("work is done")
...(2)>   end
...(2)>
...(2)>   defp greeter do
...(2)>     Process.sleep(1000)
...(2)>     IO.puts("Hello")
...(2)>     greeter()
...(2)>   end
...(2)> end
warning: redefining module Greeter (current version defined in memory)
iex:2

{:module, Greeter,
<<70, 79, 82, 49, 0, 0, 6, 208, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 221,                                                                                           
  0, 0, 0, 23, 14, 69, 108, 105, 120, 105, 114, 46, 71, 114, 101, 101, 116,                                                                                              
  101, 114, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:greeter, 0}}                                                                                                     
iex(3)> spawn fn -> Greeter.run() end
#PID<0.145.0>
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
iex(4)>
1 Like

Although if you had started the task with Task.async_no_link the task would keep running because it wouldn’t die when the other process does.

2 Likes

Ah that makes sense! I was assuming it’s due to iex. Big thanks for the confirmation :slight_smile:

1 Like