我如何在我的 Elixir 应用程序中找到工作人员?
How do I find the workers in my Elixir application?
完成入门教程的 Supervisor and Application 部分后,我正在为底部的监督树问题编写单元测试。我尝试启动顶级主管但失败并出现此错误:
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。有什么方法可以从中获取根主管进程,还是我必须在某个地方手动注册它才能从测试中获取它?
或者有没有办法直接从他们的名字中获取工人?我试过 :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
在克隆了你的 repo 之后,我环顾四周。我无法启动应用程序。通常 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
这意味着在第 5 行的 lib/kv.ex
中,您的应用程序调用了名为 KV.Supervisor
的主管。我查看了您的代码,没有模块具有该名称,但我看到您有模块使用名为 KV.Bucket.Supervisor
的主管行为。
您需要定义一个名为 KV.Supervisor
的模块来实现主管行为,或者更新 lib/kv.ex
中的第 5 行,以便它调用 KV.Bucket.Supervisor.start_link
而不是 KV.Supervisor.start_link
.
一旦你这样做,你应该能够通过调用这个来获得主管正在监督的所有进程:
Supervisor.which_children(KV.Supervisor) # Pass in the name of your supervisor module
希望对您有所帮助!
您找不到 KV.Registry,因为您的代码中有错字。您致电:
worker(KV.Registry, [@manager_name, [name: @registry_name]])
但定义是:
def start_link(event_manager, buckets_supervisor, opts \ []) do
因此您将 [name: KV.Registry] 作为 buckets_supervisor 传递,opts 是 [],因此您的工作人员未以 KV.Registry.
这个名字注册
试试这个补丁:https://github.com/mprymek/kv/commit/03ce2e4e5ab4287db2fab6de0bb1aeaf0226346f
iex(1)> :erlang.whereis KV.Registry
#PID<0.111.0>
如果你启动 supervisor 给它一个名字,你可以得到所有的工人:
Supervisor.which_children(MyApp.Supervisor)
可能发生的情况是您正在尝试启动两个 worker(GenEvent, ...)
,并且它们将有重复的事件。显式传递 :id
选项可能会修复它。
完成入门教程的 Supervisor and Application 部分后,我正在为底部的监督树问题编写单元测试。我尝试启动顶级主管但失败并出现此错误:
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。有什么方法可以从中获取根主管进程,还是我必须在某个地方手动注册它才能从测试中获取它?
或者有没有办法直接从他们的名字中获取工人?我试过 :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
在克隆了你的 repo 之后,我环顾四周。我无法启动应用程序。通常 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
这意味着在第 5 行的 lib/kv.ex
中,您的应用程序调用了名为 KV.Supervisor
的主管。我查看了您的代码,没有模块具有该名称,但我看到您有模块使用名为 KV.Bucket.Supervisor
的主管行为。
您需要定义一个名为 KV.Supervisor
的模块来实现主管行为,或者更新 lib/kv.ex
中的第 5 行,以便它调用 KV.Bucket.Supervisor.start_link
而不是 KV.Supervisor.start_link
.
一旦你这样做,你应该能够通过调用这个来获得主管正在监督的所有进程:
Supervisor.which_children(KV.Supervisor) # Pass in the name of your supervisor module
希望对您有所帮助!
您找不到 KV.Registry,因为您的代码中有错字。您致电:
worker(KV.Registry, [@manager_name, [name: @registry_name]])
但定义是:
def start_link(event_manager, buckets_supervisor, opts \ []) do
因此您将 [name: KV.Registry] 作为 buckets_supervisor 传递,opts 是 [],因此您的工作人员未以 KV.Registry.
这个名字注册试试这个补丁:https://github.com/mprymek/kv/commit/03ce2e4e5ab4287db2fab6de0bb1aeaf0226346f
iex(1)> :erlang.whereis KV.Registry
#PID<0.111.0>
如果你启动 supervisor 给它一个名字,你可以得到所有的工人:
Supervisor.which_children(MyApp.Supervisor)
可能发生的情况是您正在尝试启动两个 worker(GenEvent, ...)
,并且它们将有重复的事件。显式传递 :id
选项可能会修复它。