Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the workers in my Elixir application?

Working through the Supervisor and Application part of the Getting Started tutorial, I'm writing a unit test for the supervision tree problem at the bottom. I tried starting the top-level supervisor but it failed with this error:

  1) test all buckets die if registry dies (KV.SupervisorTest)
     test/kv/supervisor_test.exs:4
     ** (EXIT from #PID<0.111.0>) shutdown: failed to start child: GenEvent
         ** (EXIT) already started: #PID<0.75.0>

Apparently the app is already started, so I need to get access to its worker processes. I could use Supervisor.which_children to get them if I had the supervisor. To get that, maybe it would help to have the running kv application:

iex(28)> kvpid = :application.info[:running][:kv]
#PID<0.77.0>

So now I have the PID for the app. Is there some way to get the root supervisor process from this, or do I have to manually register it somewhere to get at it from the test?

Or is there a way to directly get the workers from their names? I tried :erlang.whereis but it doesn't find the worker:

iex(33)> :erlang.whereis KV.Registry
:undefined

I tried using the name of the module directly, but that doesn't work either:

test "all buckets die if registry dies" do
    reg = KV.Registry
    KV.Registry.create(reg, "shopping")
    {:ok, shopping_bucket} = KV.Registry.lookup(reg, "shopping")

    Process.exit(reg, :shutdown)
    assert_receive {:exit, "shopping", ^shopping_bucket}
end

It fails with this error:

1) test all buckets die if registry dies (KV.SupervisorTest)
   test/kv/supervisor_test.exs:4
   ** (ArgumentError) argument error
   stacktrace:
     :erlang.send(KV.Registry, {:"$gen_cast", {:create, "shopping"}})
     (elixir) lib/gen_server.ex:424: GenServer.do_send/2
     test/kv/supervisor_test.exs:6

The code is up on github.

like image 672
ijt Avatar asked Mar 03 '15 20:03

ijt


2 Answers

You can't find KV.Registry because there's a typo in your code. You call:

worker(KV.Registry, [@manager_name, [name: @registry_name]])

but the definition is:

def start_link(event_manager, buckets_supervisor, opts \\ []) do

So you pass [name: KV.Registry] as buckets_supervisor, opts is [] and your worker is therefore not registered under the name KV.Registry.

Try this patch: https://github.com/mprymek/kv/commit/03ce2e4e5ab4287db2fab6de0bb1aeaf0226346f

 iex(1)> :erlang.whereis KV.Registry
 #PID<0.111.0>
like image 97
Miroslav Prymek Avatar answered Sep 28 '22 16:09

Miroslav Prymek


If you start the supervisor given it a name, you can get all workers with:

Supervisor.which_children(MyApp.Supervisor)

What is likely happening is that you are trying to start two worker(GenEvent, ...) and they will have duplicated events. Passing the :id option explicitly will likely fix it.

like image 36
José Valim Avatar answered Sep 28 '22 15:09

José Valim