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
In your Workers.Application
when starting Supervisor
s, you'r providing unique id
s, but they also should have unique name
s.
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