【问题标题】:Supervised genstage worker on genstage documentation not working correctly?受监督的 genstage 文档上的 genstage 工作人员无法正常工作?
【发布时间】:2018-12-04 21:09:29
【问题描述】:

https://hexdocs.pm/gen_stage/GenStage.html#module-init-and-subscribe_to,我使用subscribe_to 选项定义GenStage 模块

defmodule A do
  use GenStage

  def start_link(number) do
    GenStage.start_link(A, number)
  end

  def init(counter) do
    {:producer, counter}
  end

  def handle_demand(demand, counter) when demand > 0 do
    # If the counter is 3 and we ask for 2 items, we will
    # emit the items 3 and 4, and set the state to 5.
    events = Enum.to_list(counter..counter+demand-1)
    {:noreply, events, counter + demand}
  end
end

defmodule B do
  use GenStage

  def start_link(number) do
    GenStage.start_link(B, number)
  end

  def init(number) do
    {:producer_consumer, number, subscribe_to: [{A, max_demand: 10}]}
  end

  def handle_events(events, _from, number) do
    events = Enum.map(events, & &1 * number)
    {:noreply, events, number}
  end
end

defmodule C do
  use GenStage

  def start_link() do
    GenStage.start_link(C, :ok)
  end

  def init(:ok) do
    {:consumer, :the_state_does_not_matter, subscribe_to: [B]}
  end

  def handle_events(events, _from, state) do
    # Wait for a second.
    Process.sleep(1000)

    # Inspect the events.
    IO.inspect(events)

    # We are a consumer, so we would never emit items.
    {:noreply, [], state}
  end
end

如果我手动运行它们,它可以工作

iex(1)> GenStage.start_link(A, 0, name: A)
{:ok, #PID<0.195.0>}
iex(2)> GenStage.start_link(B, 2, name: B)
{:ok, #PID<0.197.0>}
iex(3)> GenStage.start_link(C, :ok)
{:ok, #PID<0.199.0>}
[0, 2, 4, 6, 8]
[10, 12, 14, 16, 18]
[20, 22, 24, 26, 28]
[30, 32, 34, 36, 38]
‘(*,.0’

然后它建议可以将其添加到主管树中:

在监督树中,这通常通过启动多个 工人:

defmodule TestDep.Application do
  @moduledoc false

  use Application

  def start(_type, _args) do
    import Supervisor.Spec

    children = [
      worker(A, [0]),
      worker(B, [2]),
      worker(C, []),
    ]
    opts = [strategy: :rest_for_one]
    Supervisor.start_link(children, opts)
  end
end

这是我的主管树,但是当使用 iex -S mix 运行应用程序时,我收到:

** (Mix) 无法启动应用程序 testdep:TestDep.Application.start(:normal, []) 返回错误:关机: 未能启动孩子:B ** (EXIT) 无进程:进程不活跃或当前没有与给定名称关联的进程,可能是因为它的 应用程序未启动

我的应用在mix.ex 上定义为

def application do
[
extra_applications: [:logger],
mod: {TestDep.Application, []}
]
end

我有什么遗漏吗?

【问题讨论】:

    标签: elixir erlang-supervisor genstage


    【解决方案1】:

    如果我手动运行它们,它可以工作

    它没有:( 有效的不是您想要测试的,也不等同于您在监督树中开始的,这是:

    A.start_link(0)
    B.start_link(2)
    C.start_link()
    

    也就是说,您可能希望将 names 传递给包装好的 GenStage.start_link

    defmodule A do
      use GenStage
    
      def start_link(number) do
        #                            ⇓⇓⇓⇓⇓⇓⇓⇓⇓ THIS
        GenStage.start_link(A, number, name: A)
      end
    

    其余的也一样。

    【讨论】:

    • 就是这样,文档只告诉您修改 init() 方法,您可以使用进程名称调用 GenStage.start_link(A, 0, name: A) 方法,但没有明确说明更新 start_link 方法...不确定是否认为它不完整(对于像我这样的傻瓜)
    • 嗯,GenStage.init/1#consumer-and-producer_consumer-options 上的文档有点混乱,因为它没有提到它应该是 module name 而不是 name module,默默地假设每个GenServer 都默认以name: __MODULE__ 参数启动。
    • 一个问题,这对消费者来说是不需要的吧? (模块 C),因为它们不会被订阅。我已经测试过这只是更新模块 A 和 B 并且可以工作。
    • 需要它的唯一原因是能够通过其名称引用GenServer。您的代码在B(指Asubscribe_to: [{A, max_demand: 10}])和C(指Bsubscribe_to: [B])中执行此操作。所以您不需要命名的C,但它是name: __MODULE__无处不在的好习惯。
    猜你喜欢
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2021-05-22
    相关资源
    最近更新 更多