Infinite loop starting a Task worker on supervisor tree

Hi everyone

I have a worker like

defmodule Tasksup.Worker do
  use Task

  def start_link(arg) do
    Task.start_link(__MODULE__, :run, [arg])
  end

  def run(arg) do
    IO.inspect(arg)
  end
end

That is started on supervisor tree

def start(_type, _args) do
  children = [
    # {Tasksup.Worker, "Hello World"},
    %{id: :task_sup, start: {Tasksup.Worker, :start_link, ["Hello World"]}}
  ]

  # See https://hexdocs.pm/elixir/Supervisor.html
  # for other strategies and supported options
  opts = [strategy: :one_for_one, name: Tasksup.Supervisor]
  Supervisor.start_link(children, opts)
end

It works if I use {Tasksup.Worker, "Hello World"} child spec but when I use %{id: :task_sup, start: {Tasksup.Worker, :start_link, ["Hello World"]}} it starts a infinite loop until crash the application.

➜  tasksup mix run --no-halt
Compiling 3 files (.ex)
Generated tasksup app
"Hello World"
"Hello World"
"Hello World"
"Hello World"

17:45:20.252 [info]  Application tasksup exited: shutdown

Is it a bug or the expected behavior?

The default child_spec function generated by saying use Task will return a map like this:

%{id: Tasksup.Worker, restart: :temporary, start: {Tasksup.Worker, :start_link, [[]]}}

If you don’t specify restart when writing the map out manually, Supervisor will instead use :permanent, which will cause the task to be re-launched immediately after it shuts down - causing the behavior you’re seeing.

3 Likes

Thank you!