title: Detecting Elixir/OTP supervisor child spawn and termination
body: <p>I am building a job queue in Elixir as an academic exercise. Currently my workers have to manually register themselves with the queue when they're created (See <code>MyQuestion.Worker.start_link</code>).</p>
  
  <p>I'd like my supervisor to register the available workers with the queue when they are created/restart as this seems like it would aid testing of workers and minimise coupling. </p>
  
  <p>Is there a way to do what I've described in the code below in <code>MyQuestion.Supervisor</code>?</p>
  
  <pre><code>defmodule MyQuestion.Supervisor do
    use Supervisor
  
    def start_link do
      supervisor = Supervisor.start_link(__MODULE__, :ok)
    end
  
    def init(:ok) do
      children = [
        worker(MyQuestion.JobQueue, []),
        worker(MyQuestion.Worker, [], id: :worker_0),
        worker(MyQuestion.Worker, [], id: :worker_1)]
      supervise(children, strategy: :rest_for_one)
    end
  
    # LOOKING FOR SOMETHING LIKE THIS
    # on worker spawn, I want to add the worker to the queue
    def child_spawned(pid, {MyQuestion.Worker, _, _}) do
      # add worker to queue
      MyQuestion.JobQueue.add_new_worker(pid)
    end
  
    # LOOKING FOR SOMETHING LIKE THIS
    # I want some way to do the following (imagine the callback existed)
    def child_terminated(pid, reason, state) 
      # with this information I could tell the job queue to mark 
      # the job associated with the pid as failed and to retry
      # or maybe extract the job id from the worker state, etc.
      MyQuestion.JobQueue.remove_worker(pid)
      MyQuestion.JobQueue.restart_job_for_failed_worker(pid)
    end
  
  end
  
  defmodule MyQuestion.JobQueue do
    def start_link do
      Agent.start_link(fn -&gt; [] end, name: __MODULE__)
    end
  
    def new_worker(pid) do
      # register pid with agent state in available worker list, etc.
    end
  
    def add_job(job_description) do
      # find idle worker and run job
      &lt;... snip ...&gt;
    end
  
    &lt;... snip ...&gt;
  end
  
  defmodule MyQuestion.Worker do
    use GenServer
    def start_link do
      # start worker
      {:ok, worker} = GenServer.start_link(__MODULE__, [])
  
      # Now we have a worker pid, so we can register that pid with the queue
      # I wish this could be in the supervisor or else where.
      MyQuestion.JobQueue.add_new_worker(worker)
  
      # must return gen server's start link
      {:ok, worker}
    end
  
    &lt;... snip ...&gt;
  end
  </code></pre>