Состояние "завершается с ошибкой" нет процесса ". Любые предложения?
Согласно Документам супервизора , список children
:
children = [
{Updates, name: Updates},
{State, name: State}
]
должен представлять собой список из child specification
кортежей, где дочерняя спецификация имеет следующие допустимые ключи:
Дочерняя спецификация содержит 6 ключей. Первые два необходимы, иостальные необязательны:
: id - любой термин, используемый для внутренней идентификации дочерней спецификации супервизором; по умолчанию используется данный модуль. В случае конфликтующих значений: id супервизорОткажется от инициализации и потребует явных идентификаторов. Этот ключ необходим.
: start - кортеж с аргументами module-function-args для запуска дочернего процесса.требуется.
: restart - атом, который определяет, когда завершить дочерний процесс должен быть перезапущен (см. раздел «Значения перезапуска» ниже). Этот ключ является необязательным и по умолчанию: постоянный.
: shutdown - атом, который определяет, как дочерний процесс должен быть завершен (см. Раздел «Значения выключения» ниже).Этот ключ является необязательным и по умолчанию равен 5000, если типом является: worker или: infinity, если типом является: supervisor.
: type - указывает, что дочерний процесс является: worker или a:руководитель.Этот ключ является необязательным и по умолчанию: worker.
Существует шестой ключ, : modules , который редко изменяется.Он устанавливается автоматически в зависимости от значения в: start.
Обратите внимание, что нет клавиши name:
, которую вы указываете в своих дочерних спецификациях.
Однако GenServer.start_link()
имеет опцию name:
:
И start_link / 3, и start / 3 поддерживают GenServer для регистрации имени при запуске с помощью опции: name.Зарегистрированные имена также автоматически очищаются при расторжении.Поддерживаемые значения:
атом - GenServer зарегистрирован локально с заданным именем, используя Process.register / 2.
{: global, term} - GenServer зарегистрирован глобально с данным термином, используя функции в: global module.
{: via, module, term} - GenServer зарегистрирован вданный механизм и имя.Опция: via ожидает модуль, который экспортирует имя_регистра / 2, имя_регистра / 1, имя_сайта / 1 и отправить / 2.Одним из таких примеров является: global модуль, который использует эти функции для хранения списка имен процессов и связанных с ними PID, которые доступны глобально для сети узлов Elixir.Elixir также поставляется с локальным, децентрализованным и масштабируемым реестром, который называется Registry для локального хранения имен, которые генерируются динамически.
Например, мы можем запустить и зарегистрировать наш сервер Stack локально следующим образом:
# Start the server and register it locally with name:
MyStack {:ok, _} = GenServer.start_link(Stack, [:hello], name: MyStack)
Итак, я думаю, что вы должны делать что-то вроде этого:
def init(_arg) do
children = [
Updates,
State
]
Затем в ваших функциях start_link () GenServer:
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
======
Вот полный пример.В application.ex
вы можете указать имена, которые хотите зарегистрировать:
children = [
# Starts a worker by calling: Servers.Worker.start_link(arg)
# {Servers.Worker, arg},
{
Servers.CurrentState, [
init_state_with: [:hello, 10],
name_to_register: Servers.CurrentState
]
},
{
Servers.Updates, [
init_state_with: [:goodbye],
name_to_register: Servers.Updates
]
}
]
Тогда вы сможете определить два ваших GenServer следующим образом:
lib / servers / updates.ex:
defmodule Servers.Updates do
use GenServer
def start_link(arg) do
GenServer.start_link(
__MODULE__,
arg[:init_state_with],
name: arg[:name_to_register])
end
## Callbacks
@impl true
def init(state) do
{:ok, state}
end
@impl true
def handle_call(:get_updates, _from, state) do
{:reply, state, state}
end
@impl true
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
##User interface:
def get() do
GenServer.call(__MODULE__, :get_updates)
end
def add(item) do
GenServer.cast(__MODULE__, {:push, item})
end
end
lib / servers / current_state.ex:
defmodule Servers.CurrentState do
use GenServer
def start_link(args) do
GenServer.start_link(
__MODULE__,
args[:init_state_with],
name: args[:name_to_register])
end
## Callbacks
@impl true
def init(state) do
IO.inspect(state, label: "The CurrentState server is starting with state")
{:ok, state}
end
@impl true
def handle_call(:get_state, _from, state) do
state_to_add = Servers.Updates.get()
new_state = state_to_add ++ state
{:reply, new_state, new_state}
end
##User interface:
def get() do
GenServer.call(__MODULE__, :get_state)
end
end
Тогда, вы можете проверить вещи с помощью:
defmodule Servers.Go do
def test() do
IO.inspect("Updates has state: #{inspect Servers.Updates.get()}" )
IO.inspect("CurrentState has state: #{inspect Servers.CurrentState.get()}" )
:ok
end
end
В iex:
~/elixir_programs/servers$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Compiling 1 file (.ex)
The CurrentState server is starting with state: [:hello, 10]
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Servers.Go.test()
"Updates has state: [:goodbye]"
"CurrentState has state: [:goodbye, :hello, 10]"
:ok
iex(2)>
(обратите внимание, что первая строка вывода смешана с сообщениями запуска сервера.)
Однако вы можете использовать __MODULE__
для упрощения вещей:
application.ex :
children = [
# Starts a worker by calling: Servers.Worker.start_link(arg)
# {Servers.Worker, arg},
{ Servers.CurrentState, [:hello, 10] }
{ Servers.Updates, [:goodbye] }
]
lib / servers / updates.ex :
defmodule Servers.Updates do
use GenServer
def start_link(arg) do
#arg comes from child specification tuple
#inside the `children` list in application.ex
# | module where the GenServer is defined
# |
# | | send arg to the GenServer's init() function
# V V
GenServer.start_link(__MODULE__, arg, name: __MODULE__)
# ^
# |
# register the specified name for this GenServer
end
## Callbacks
@impl true
def init(state) do
{:ok, state}
end
@impl true
def handle_call(:get_updates, _from, state) do
{:reply, state, state}
end
@impl true
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
## User interface:
def get() do
GenServer.call(__MODULE__, :get_updates)
end
def add(item) do
GenServer.cast(__MODULE__, {:push, item})
end
end
lib / servers / current_state.ex:
defmodule Servers.CurrentState do
use GenServer
def start_link(arg) do
#arg comes from child specification tuple
#inside the `children` list in application.ex
# | module where the GenServer is defined
# |
# | | send arg to the GenServer's init() function
# V V
GenServer.start_link(__MODULE__, arg, name: __MODULE__)
# ^
# |
# register the specified name for this GenServer
end
## Callbacks
@impl true
def init(state) do
IO.inspect(state, label: "The CurrentState server is starting with state")
{:ok, state}
end
@impl true
def handle_call(:get_state, _from, state) do
state_to_add = Servers.Updates.get()
new_state = state_to_add ++ state
{:reply, new_state, new_state}
end
## User interface:
def get() do
GenServer.call(__MODULE__, :get_state)
end
end