簡體   English   中英

了解 Elixir badarg 錯誤消息

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM