[英]Understanding Elixir badarg error message
当尝试从DynamicSupervisor
启动我的进程时,我收到以下错误:
{:error,
{:EXIT,
{:badarg,
[
{:erlang, :apply,
[
BfgEngine.MarketService,
:start_link,
{{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000,
:worker, [BfgEngine.MarketService]}
], []},
{:supervisor, :do_start_child_i, 3, [file: 'supervisor.erl', line: 379]},
{:supervisor, :handle_call, 3, [file: 'supervisor.erl', line: 404]},
{:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 661]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 690]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
]}}}
我使用的代码是:
def start_market(market_id) do
spec = {MarketService, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
但是,我不清楚出了什么问题。 哪个函数的哪个参数不正确? 如何分解并阅读给定的错误消息?
更新:
这是我的主管的 init 方法:
@impl true
def init(initial_arg) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: [initial_arg]
)
end
更新2:这是market_service的start_link:
def start_link(market_id) when is_bitstring(market_id) do
GenServer.start_link(__MODULE__, market_id, name: via_tuple(market_id))
end
即时通讯使用默认child_spec
IM从得到GenServer
更新 3:更改为:
def start_market(market_id) do
spec = {MarketService, market_id: market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
给出:
{:error,
{:undef,
[
{BfgEngine.MarketService, :start_link, [[], [market_id: "222"]], []},
{DynamicSupervisor, :start_child, 3,
[file: 'lib/dynamic_supervisor.ex', line: 654]},
{DynamicSupervisor, :handle_start_child, 2,
[file: 'lib/dynamic_supervisor.ex', line: 640]},
{:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 661]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 690]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
]}}
更改为:
def start_market(market_id) do
spec = {MarketService, :market_id, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
给出:
** (ArgumentError) supervisors expect each child to be one of:
* a module
* a {module, arg} tuple
* a child specification as a map with at least the :id and :start fields
* or a tuple with 6 elements generated by Supervisor.Spec (deprecated)
Got: {BfgEngine.MarketService, :market_id, "222"}
(elixir) lib/supervisor.ex:657: Supervisor.init_child/1
(elixir) lib/supervisor.ex:744: Supervisor.child_spec/2
(elixir) lib/dynamic_supervisor.ex:304: DynamicSupervisor.start_child/2
你有badarg
例外功能erlang:apply/3
时,有三个参数BfgEngine.MarketService
, :start_link
和{{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
并且它发生在函数supervisor:do_start_child_i/3
。
函数erlang:apply/3
应该是 MFA aka Module, Function, Arguments。 {{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
不是参数,因为它显然不是参数列表。 从您的代码中,我可以猜测错误是变量spec
的内容。 您应该提供一些 proplist 或地图。 我不知道,你应该仔细阅读DynamicSupervisor
的文档。
关于 Elixir 抛出的错误信息的理解,可以参考Erlang 官方文档。 Learn You Some Erlang For Great Good 中关于错误和异常的部分可以提供帮助。 @Hynek -Pichi Vychodil
的回答也很准确。
正如@Milan Jaric
提到的,您的错误将来自:
def start_market(market_id) do
spec = {MarketService, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
但不仅如此! DynamicSupervisor.start_child(__MODULE__, spec)
正在调用MarketService.start_link/1
! 您的问题在于 DynamicSupervisor 模块中的此函数的组合,以及您在 MarketService.start_link/1 中解析值的方式:
def start_link(market_id) when is_bitstring(market_id) do
GenServer.start_link(__MODULE__, market_id, name: via_tuple(market_id))
end
事实上,如果您还正确实现了 MarketService.init/1,此代码应该可以工作。 我无法重现该错误。 你确定market_id
真的是一个位串吗?
就个人而言,我的代码基于官方文档:
defmodule MySupervisor do
use DynamicSupervisor
def start_link(init_arg) do
DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
def start_child(foo, bar, baz) do
# If MyWorker is not using the new child specs, we need to pass a map:
# spec = %{id: MyWorker, start: {MyWorker, :start_link, [foo, bar, baz]}}
spec = {MyWorker, foo: foo, bar: bar, baz: baz}
DynamicSupervisor.start_child(__MODULE__, spec)
end
@impl true
def init(init_arg) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: [init_arg]
)
end
end
如您所见,他们建议在此处使用关键字列表:
spec = {MyWorker, foo: foo, bar: bar, baz: baz}
仅当您按如下方式实现MyWorker.start_link/1
:
def start_link(args) do
foo = Keyword.fetch!(args, :foo)
bar = Keyword.fetch!(args, :bar)
baz = Keyword.fetch!(args, :baz)
Genserver.start_link(__MODULE__, {foo, bar, baz}, [])
def init({foo, bar, baz}) do
# do something...
state = {foo, bar, baz}
{:ok, state}
在您的情况下,如果您将 start_market/1 更改为:
def start_market(market_id) do
spec = {MarketService, market_id: market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
它不会工作,因为这个 MarketService.start_link/1 会失败:
def start_link(market_id) when is_bitstring(market_id) do
GenServer.start_link(__MODULE__, market_id, name: via_tuple(market_id))
end
这里的market_id 不是位bitstring
而是关键字列表。 因此,您必须将 MarketService.start_link/1 函数修改为:
def start_link(args) when is_list(args) do
market_id = Keyword.fetch!(args, :market_id)
GenServer.start_link(__MODULE__, market_id, name: via_tuple(market_id))
end
并写一个 MarketService.init/1 如下:
def init(market_id) do
# do something... Let's keep it simple for the example:
state = market_id
{:ok, state}
end
从发布的代码中很难判断,但是您可以尝试将start_market
更改为:
def start_market(market_id) do
spec = {MarketService, :market_id, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
更新(以下是两个选项):
def start_market(market_id) do
spec = &{
id: MarketService,
start: {MarketService, start_link, [market_id]},
type: :worker
}
DynamicSupervisor.start_child(__MODULE__, spec)
end
或者
def start_market(market_id) do
spec = {MarketService, [market_id]}
DynamicSupervisor.start_child(__MODULE__, spec)
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.