Difference between Task.Supervisor.start_child vs Task.start

I think the confusion results from understanding what a “shutdown” is.

Here’s one line where that confusion resides in the docs of Task.start/1:

If the current node is shutdown, the node will terminate even if the task was not completed

What is “the current node”? What makes the current node shutdown? What qualifies as a shutdown or not? How do you start a shutdown?

When you run iex -S mix you are starting and sustaining a vm node[0] that the Task child process resides in. So the spawned Task will continue to completion even after Foo.foo terminates. Compared to mix run -e Foo.foo which halts the vm node.

If you look at the docs of mix run you’ll see the --no-halt option. That’s because, by default, mix run halts the running system/node, which is different from a shutdown.

More details on what halt does from System.halt:

Terminates the Erlang runtime system without properly shutting down applications and ports. Please see stop/1 for a careful shutdown of the system.

So, I think the confusion here is understanding how a System/node starts and how a System/node stops.
Here’s a thread that may be of interest to you, to simulate a shutdown. In particular:

if you want to politely shutdown your system, you should invoke :init.stop, which will recursively shutdown the supervision tree causing terminate callbacks to be invoked

This is why in the docs it’s recommended to use Task.Supervisor as, I imagine, if you do a shutdown, it won’t take into account any outstanding Task.start processes.

[0] https://elixir-lang.org/getting-started/mix-otp/distributed-tasks.html

3 Likes