I’m sure I’m missing something obvious here – hopefully someone can point out what it is!
I’ve got an application (Phoenix, but I don’t think that’s relevant) that uses a Task.Supervisor
to supervise a number of long-running scheduled tasks in the background.
This all works fine, but when I shut the application down the supervisor and its child tasks are killed immediately, whereas I’d like the supervisor to wait for the tasks to complete (or until it reaches the :shutdown
value in its child spec) before terminating. My assumption was that if I put the scheduler that triggers the tasks last in the main application’s child list, preceded by the task supervisor, then when shutdown was requested (eg by :init.stop()
), no new tasks would start, running ones would complete, then the rest of the application would shutdown.
I’ve reproduced this in a simple (mix new --sup
) application:
defmodule MyApp.Application do
use Application
@impl true
def start(_type, _args) do
children = [
{Task.Supervisor, name: MyApp.TaskSupervisor}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
iex(1)> Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
...(1)> Process.sleep(:timer.seconds(5))
...(1)> IO.puts("Finished!")
...(1)> end)
{:ok, #PID<0.151.0>}
iex(2)> :init.stop()
:ok
iex(3)>
$
The IEX shell terminates more-or-less instantly on running :init.stop()
, and the task never completes.