I want to start a Task.Supervisor with my application and put the first Task child in it. Any good ideas about how to structure this?
I’ve thought of having a line like this in the supervisor specification:
supervisor(Tricky, [])
Then defining the Tricky module as something like:
defmodule Tricky do
def start_link do
result = Task.Supervisor.start_link
if is_tuple(result) and elem(result, 0) == :ok do
elem(result, 1) |> Task.Supervisor.start_child(…)
end
result
end
end
I tend to reach for GenServers more quickly than Tasks and Agents. However, in a more tactical sense, is there something wrong with this?
{:ok, sup_pid} = result = Task.Supervisor.start_link
Task.Supervisor.start_child(sup_pid, ...)
result
I mean, if the supervisor doesn’t start correctly and you get an {:error, reason} result, does it really matter if you get a match exception here or not?
Edit more commentary: I find elem calls to be a cautionary code smell. Your code is rather defensive. Mine is more assertive in a “let it crash” sense, which is more idiomatic Elixir IMHO.
It might matter in some cases. The one that comes to mind is {:error, {:already_started, pid}}, which might be useful to a caller. So, I’d rather propagate the error in a standard way ({:error, reason}), than crash here:
with {:ok, sup_pid} <- Task.Supervisor.start_link(...) do
do_something_with(sup_pid)
{:ok, sup_pid}
end