Контролируемый гензажный работник по документации по генезиту не работает правильно? - PullRequest
0 голосов
/ 26 июня 2018

В https://hexdocs.pm/gen_stage/GenStage.html#module-init-and-subscribe_to Я определяю модули GenStage с опцией subscribe_to

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, []) возвратил ошибку: shutdown: не удалось запуститьпотомок: B ** (EXIT) нет процесса: процесс не активен или нет процесса, связанного с данным именем, возможно, потому что его приложение не запущено

Мое приложение определено в mix.ex как

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

Что-то мне не хватает?

1 Ответ

0 голосов
/ 26 июня 2018

Если я запускаю их вручную, это работает

Это не так :( То, что работает, - это не то, что вы хотели проверить, и это не то, что вы запускаете в дереве контроля, это:

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

Тем не менее, вы, вероятно, захотите передать имен обернутым GenStage.start_link:

defmodule A do
  use GenStage

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

И то же самое для остальных.

...