How to gracefully handle errors in supervised children initialisation

If my supervised init callback wants to fail, it can return {:stop, reason}, but that seems to stop by supervisor as well.

Is that because of this :

If the start function of any of the child processes fails or returns an error tuple or an erroneous value, the supervisor first terminates with reason :shutdown all the child processes that have already been started, and then terminates itself and returns {:error, {:shutdown, reason}}.

https://hexdocs.pm/elixir/Supervisor.html#start_link/2

If so, is there a way to exit from the init to stop the supervised child, and keep the main supervisor alive?

Example code :

defmodule App.Supervisor do
  use Supervisor

  def start_link() do
    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_) do
    children = [
      supervisor(App.ChildSupervisor, [])
    ]

    supervise(children, strategy: :one_for_one)
  end
end

defmodule App.ChildSupervisor do
  use Supervisor

  def init do
    {:stop, "reason"}
  end
end

Are you searching for :ignore?

GenServer.init/1:

Returning :ignore will cause start_link/3 to return :ignore and the
process will exit normally without entering the loop or calling c:terminate/2.
If used when part of a supervision tree the parent supervisor will not fail
to start nor immediately try to restart the GenServer. The remainder of the
supervision tree will be (re)started and so the GenServer should not be
required by other processes. It can be started later with
Supervisor.restart_child/2 as the child specification is saved in the parent
supervisor. The main use cases for this are:

  • The GenServer is disabled by configuration but might be enabled later.
  • An error occurred and it will be handled by a different mechanism than the
    Supervisor. Likely this approach involves calling Supervisor.restart_child/2
    after a delay to attempt a restart.
3 Likes