[英]Understanding Elixir badarg error message
When trying to start my process from a DynamicSupervisor
im getting the following error:当尝试从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]}
]}}}
The code im using is:我使用的代码是:
def start_market(market_id) do
spec = {MarketService, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
However it is not clear to me what is going wrong.但是,我不清楚出了什么问题。 What argument to which function is it thats not correct?哪个函数的哪个参数不正确? How do I break down and read the given error message?如何分解并阅读给定的错误消息?
Update:更新:
This is the init method of my supervisor:这是我的主管的 init 方法:
@impl true
def init(initial_arg) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: [initial_arg]
)
end
Update 2: This is the start_link of market_service:更新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
Im using the default child_spec
im getting from GenServer
即时通讯使用默认child_spec
IM从得到GenServer
Update 3: Changing to:更新 3:更改为:
def start_market(market_id) do
spec = {MarketService, market_id: market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
Gives:给出:
{: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]}
]}}
Changing to:更改为:
def start_market(market_id) do
spec = {MarketService, :market_id, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
Gives:给出:
** (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
You got badarg
exception to function erlang:apply/3
when there are three arguments BfgEngine.MarketService
, :start_link
and {{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
and it happen in function supervisor:do_start_child_i/3
.你有badarg
例外功能erlang:apply/3
时,有三个参数BfgEngine.MarketService
, :start_link
和{{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
并且它发生在函数supervisor:do_start_child_i/3
。
The arguments to the function erlang:apply/3
should be MFA aka Module, Function, Arguments.函数erlang:apply/3
应该是 MFA aka Module, Function, Arguments。 {{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
is not Arguments because it obviously is not a list of arguments . {{BfgEngine.MarketService, :start_link, ["1111"]}, :permanent, 5000, :worker, [BfgEngine.MarketService]}
不是参数,因为它显然不是参数列表。 From your code, I can guess the error is the content of variable spec
.从您的代码中,我可以猜测错误是变量spec
的内容。 You should provide some proplist or map.您应该提供一些 proplist 或地图。 I don't know, you should read the documentation of DynamicSupervisor
more carefully.我不知道,你应该仔细阅读DynamicSupervisor
的文档。
As of understanding the error message thrown by Elixir, you can refer to the official Erlang documentation .关于 Elixir 抛出的错误信息的理解,可以参考Erlang 官方文档。 The section about errors and exceptions from Learn You Some Erlang For Great Good can help. Learn You Some Erlang For Great Good 中关于错误和异常的部分可以提供帮助。 The answer of @Hynek -Pichi Vychodil
is also accurate. @Hynek -Pichi Vychodil
的回答也很准确。
As @Milan Jaric
mentioned, your error would come from:正如@Milan Jaric
提到的,您的错误将来自:
def start_market(market_id) do
spec = {MarketService, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
But not only!但不仅如此! DynamicSupervisor.start_child(__MODULE__, spec)
is calling MarketService.start_link/1
! DynamicSupervisor.start_child(__MODULE__, spec)
正在调用MarketService.start_link/1
! Your problem lies in the combination of this function from the DynamicSupervisor module, and the way you parse values in 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
Indeed, this code should work, if you also have implemented MarketService.init/1 correctly.事实上,如果您还正确实现了 MarketService.init/1,此代码应该可以工作。 I am not able to reproduce the error.我无法重现该错误。 Are you sure market_id
is really a bitstring?你确定market_id
真的是一个位串吗?
Personally, I had based my code on the official documentation :就个人而言,我的代码基于官方文档:
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
As you can see, they suggest to use a Keyword list here:如您所见,他们建议在此处使用关键字列表:
spec = {MyWorker, foo: foo, bar: bar, baz: baz}
It works only if you've implemented MyWorker.start_link/1
as follows:仅当您按如下方式实现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}
In your case, if you change start_market/1 to:在您的情况下,如果您将 start_market/1 更改为:
def start_market(market_id) do
spec = {MarketService, market_id: market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
It will not work because this MarketService.start_link/1 will fail:它不会工作,因为这个 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 here is not a bitstring
but a Keyword list.这里的market_id 不是位bitstring
而是关键字列表。 So you got to modify MarketService.start_link/1 function to:因此,您必须将 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
And write a MarketService.init/1 as follows:并写一个 MarketService.init/1 如下:
def init(market_id) do
# do something... Let's keep it simple for the example:
state = market_id
{:ok, state}
end
It is hard to tell from posted code, but could you try changing start_market
to:从发布的代码中很难判断,但是您可以尝试将start_market
更改为:
def start_market(market_id) do
spec = {MarketService, :market_id, market_id}
DynamicSupervisor.start_child(__MODULE__, spec)
end
UPDATE (Below are two options):更新(以下是两个选项):
def start_market(market_id) do
spec = &{
id: MarketService,
start: {MarketService, start_link, [market_id]},
type: :worker
}
DynamicSupervisor.start_child(__MODULE__, spec)
end
OR或者
def start_market(market_id) do
spec = {MarketService, [market_id]}
DynamicSupervisor.start_child(__MODULE__, spec)
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.