Zen
Zen

Reputation: 7385

Supervision tree failing to start

I'm trying to implement something like what is described in this answer, but I am getting errors like what I've included below when I compile the application.

** (Mix) Could not start application workers: Workers.Application.start(:normal, []) returned an error: shutdown: failed to start child: {Workers.UrlSupervisor, 2}
    ** (EXIT) already started: #PID<0.1034.0>

I'm not sure if I am inherently doing something I'm not allowed to here, or I've just made a little mistake.

For some context here are the supervisors:

defmodule Workers.Application do
  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    import Supervisor.Spec, warn: false

     url_workers =  1..100 |> Enum.map(fn (i) -> supervisor(Workers.UrlSupervisor, [i], [id: {Workers.UrlSupervisor, i}, restart: :temporary]) end)
     domain_workers = 1..100 |> Enum.map(fn (i) -> supervisor(Workers.DomainSupervisor, [i], [id: {Workers.DomainSupervisor, i}, restart: :temporary]) end)

    opts = [strategy: :one_for_one, name: Workers.Supervisor]
    Supervisor.start_link(url_workers ++ domain_workers, opts)
  end
end

defmodule Workers.UrlSupervisor do
  def start_link(id) do
    import Supervisor.Spec, warn: false

    children = [worker(Task, [&Workers.Url.worker/0], [id: {Workers.Url, id}, restart: :permanent])]

    opts = [strategy: :one_for_one, name: Workers.UrlSupervisor]
    Supervisor.start_link(children, opts)
  end
end

defmodule Workers.DomainSupervisor do
  def start_link(id) do
    import Supervisor.Spec, warn: false

    children = [worker(Task, [&Workers.Domain.worker/0], [id: {Workers.Domain, id}, restart: :permanent])]

    opts = [strategy: :one_for_one, name: Workers.DomainSupervisor]
    Supervisor.start_link(children, opts)
  end
end

And here is one of the workers (they look largely the same).

defmodule Workers.Domain do
  def worker do
    case Store.Domains.pop do
      :empty ->
        IO.puts "[Domain] none found, waiting..."
        :timer.sleep(1000)
      {crawl_id, domain} ->
        IO.puts "[Domains] found a domain to check: #{domain}"
        case Core.check_domain(domain) do
          :error ->
            Utils.insert(crawl_id, domain, false)
          :registered ->
            Utils.insert(crawl_id, domain, false)
          :available ->
            Utils.insert(crawl_id, domain, true)
        end
    end
    worker()
  end
end

Upvotes: 2

Views: 369

Answers (1)

Paweł Dawczak
Paweł Dawczak

Reputation: 9639

In your Workers.Application when starting Supervisors, you'r providing unique ids, but they also should have unique names.

Try adding another keyword, something like name: :"url_supervisor_#{i}":

def start(_type, _args) do
  import Supervisor.Spec, warn: false

  url_workers =  1..100 |> Enum.map(fn (i) -> 
    supervisor(Workers.UrlSupervisor, [i],
               [id: {Workers.UrlSupervisor, i},
                name: :"url_supervisor_#{i}", # Name added here
                restart: :temporary])
  end)
  domain_workers = 1..100 |> Enum.map(fn (i) ->
    supervisor(Workers.DomainSupervisor, [i],
               [id: {Workers.DomainSupervisor, i},
                name: :"domain_supervisor_#{i}", # Name added here
                restart: :temporary])
     end)

  opts = [strategy: :one_for_one, name: Workers.Supervisor]
  Supervisor.start_link(url_workers ++ domain_workers, opts)
end

Upvotes: 2

Related Questions