2015-03-03 4 views
8

Работая с частью учебника Getting Started, я пишу блок-тест для проблемы дерева наблюдения внизу. Я попытался начать супервизор верхнего уровня, но он не смог с этой ошибкой:Как найти работников в моем приложении Elixir?

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> 

Видимо приложение уже запущенно, так что мне нужно, чтобы получить доступ к его рабочим процессам. Я мог бы использовать Supervisor.which_children, чтобы получить их, если бы у меня был супервайзер. Для того, чтобы получить, что, может быть, это помогло бы иметь запущенный kv приложение:

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

Так что теперь у меня есть PID для приложения. Есть ли способ получить от него процесс супервизора root, или мне нужно вручную зарегистрировать его где-нибудь, чтобы получить от него тест?

Или есть способ напрямую получить рабочих от их имен? Я попытался :erlang.whereis, но он не находит работника:

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

Я пытался использовать имя модуля непосредственно, но это не работает, либо:

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 

Это терпит неудачу с этой ошибкой:

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.

+0

Чтобы получить ответвление на этот вопрос, вы должны добавить этот шаг: '$ git checkout -b s_o_question origin/s_o_find_worker_question' – ijt

ответ

7

Вы не можете найти KV.Registry, потому что в вашем коде есть опечатка. Вы звоните:

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

но определение:

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

Так вы передаете [имя: KV.Registry], как buckets_supervisor, выбирает в [] и ваш работник поэтому не зарегистрирован под именем К.В. .Registry.

Попробуйте этот патч: https://github.com/mprymek/kv/commit/03ce2e4e5ab4287db2fab6de0bb1aeaf0226346f

iex(1)> :erlang.whereis KV.Registry 
#PID<0.111.0> 
+0

P.S. если ваш код корректно функционирует, зависит от какого-либо аргумента, он, вероятно, должен быть обязательным. Если вы определили, что вы работаете как «def start_link (event_manager, buckets_supervisor, opts)», этого не произойдет. –

+0

Изменение рабочей строки сделало это: 'worker (KV.Registry, [@manager_name, @bucket_sup_name, [name: @registry_name]])' – ijt

1

После клонирования вашего репо я осмотрелся. Я не смог запустить приложение. Обычно Elixir приложения могут быть запущены из командной строки, запустив:

iex -S mix 

Но когда я запустил приложение, я получил следующее сообщение об ошибке:

** (Mix) Could not start application kv: exited in: KV.start(:normal, []) 
** (EXIT) an exception was raised: 
    ** (UndefinedFunctionError) undefined function: KV.Supervisor.start_link/0 (module KV.Supervisor is not available) 
     KV.Supervisor.start_link() 
     (kernel) application_master.erl:272: :application_master.start_it_old/4 

Это означает, что в lib/kv.ex на линии 5 ваше приложение делает вызов супервайзера по имени KV.Supervisor. Я посмотрел ваш код, и ни один модуль не получил это имя, но я вижу, что у вас есть модуль, использующий поведение супервизора с именем KV.Bucket.Supervisor.

Вам нужно будет либо определить модуль с именем KV.Supervisor, который реализует поведение супервизора, или обновление линии 5 в lib/kv.ex так она называет KV.Bucket.Supervisor.start_link вместо KV.Supervisor.start_link.

После того, как вы сделаете это, вы должны быть в состоянии получить все процессы супервизор Контроль по телефону это:

Supervisor.which_children(KV.Supervisor) # Pass in the name of your supervisor module 

Надеется, что это помогает!

+0

KV.Supervisor определяется начиная с строки 42 здесь: https://github.com/ijt /kv/blob/s_o_find_worker_question/lib/kv/supervisor.ex. Я не уверен, что понимаю. – ijt

+0

Есть еще один шаг, когда вы клонируете репо. Вы также должны проверить ветку: git checkout -b s_o_question origin/s_o_find_worker_question. – ijt

6

При запуске супервизора дал ему имя, вы можете получить все рабочие с:

Supervisor.which_children(MyApp.Supervisor) 

Что, вероятно, происходит то, что вы пытаетесь запустите два worker(GenEvent, ...), и они будут иметь дублированные события. Передача опции :id явно скорее всего исправит ее.

+0

Вот что происходит: 'iex (1)> Supervisor.which_children (KV.Supervisor) ** (выход) завершен в: GenServer.call (KV.Supervisor,: which_children,: infinity) ** (EXIT) нет процесса (эликсир) lib/gen_server.ex: 356: GenServer.call/3' even хотя я вижу, что KV.Supervisor запущен из сообщения журнала. У меня есть только один вызов «worker (GenEvent, ...)». – ijt

+0

А, я вижу. Мне нужно было изменить тело KV.Supervisor.start_link на 'Supervisor.start_link (__ MODULE__,: ok, [name: KV.Supervisor])'. Теперь ваш фрагмент работает. – ijt