Is there a reason we don't have a Supervisor.child_spec/1?


I was digging into child specs a bit to re-orient myself around how to write a nice-to-write and nice-to-read supervision tree. I find module based supervisors can get a bit hard to parse at a glance as the structure can end up spread across files.

So with the Supervisor.Spec helpers deprecated since last I looked I figured I need to get familiar with child specs in more depth.

Something that tripped me up was that Supervisor doesn’t seem to follow the child spec convention. So I can’t use:

{Supervisor, [my_children, my_opts]}

(edit: corrected example tuple)

Is there a nice and clean way of setting up a Supervisor, without a module, in the tree, beyond writing a full child_spec map? I find them visually a bit noisy, though they are quite simple and work well.

Am I missing something?

1 Like

The only supported versions in the list of children are module(), {module, arg} or :supervisor.child_spec(). There’s no tuple-3 option at all. I blogged about that system in more detail yesterday:

So you need to send everything in one arg to be sent to child_spec/1. You could do something like this:

defmodule MySupervisor do
  def child_spec(init_arg) do
    {children, opts} = extract_from_init_arg(init_arg)
      id: __MODULE__
      start: {Supervisor, :start_link, [children, opts]}
      type: :supervisor

Which would allow for {MySupervisor, some_children_and_opts_format}. If that’s actually cleaner than a private function building the child_spec manually I’m not so sure about, given that the list of children is unlikely just some small argument to place in the tuple format.

Thanks, brainfart on the 3-tuple. Edited that. As it wasn’t the point of the question.

But that MySupervisor approach was something I was thinking about, which yes. It would be cleaner to me. I’m not certain why Supervisor doesn’t offer it? But then again child_spec/2 does something fairly different. So maybe to avoid confusion?

I was annoyed by this too and at previous company wrote a helper supervisor/2 function, so I could write supervisor(children, opts) directly as a child. Perhaps submit a proposal to elixir-lang-core.

As an aside and self-ad, Parent.Supervisor supports {Parent.Supervisor, {children, opts}} and since Parent doesn’t have the concept of strategy, I think I should also support {Parent.Supervisor, children}.