Начать работу, когда запускается DynamicSupervisor - PullRequest
0 голосов
/ 29 июня 2018

Я реализовал DynamicSupervisor, который обрабатывает работников, использующих Process.send_after/3 для отправки push-уведомлений с некоторой точностью по времени.

В некоторых случаях, например, когда я выпускаю новую версию без функции «горячей замены», я хочу вести учет всех рабочих, еще не завершенных в DETS, и когда DynamicSupervisor снова начинает создавать всех этих рабочих с тем же состоянием, которое было сохранено в DETS.

Я знаю, что DynamicSupervisor не поддерживает работников с самого начала, и я должен внедрить start_child для запуска нового работника, но не знаю, как я могу интегрировать запуск DynamicSupervisor с начало работы тезисов на одном модуле.

Я пробовал разные подходы, но безуспешно (Task.async, Process.send_after и т. Д.).

Должен ли я реализовать начальное поведение в другой части кода (я использую Phoenix)?

РЕДАКТИРОВАТЬ: Я обнаружил небольшую проблему (ожидал% {x: 1, y: 2} и получал [x: 1, y: 2]

Это функция инициализации в DynamicSupervisor.

...

def init(arg) do
  Task.async(fn ->
    start_lost_children()
  end)

  DynamicSupervisor.init(arg)
end

def start_child(data) do
  spec = {MyApp.Worker, %{data: data}}

  DynamicSupervisor.start_child(__MODULE__, spec)
end

...

Это сообщение об ошибке, которое я получаю, хотя и не влияет на поведение DynamicSupervisor.

[error] DynamicSupervisor received unexpected message: {#Reference<0.2565843855.2975858690.212433>, :ok}

[error] DynamicSupervisor received unexpected message: {:DOWN, #Reference<0.2565843855.2975858690.212433>, :process, #PID<0.593.0>, :normal}

:ok является результатом возврата start_lost_children/0.

Если я реализую handle_info/2, он ничего не поймает.

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

Task.async/1 запускает задание, которое нужно ожидать. Разработчики должны в конце концов позвонить Task.await/2 или Task.yield/2.

Try Task.start/1 - это используется только в том случае, если задача используется для побочных эффектов (то есть нет интереса к возвращаемому результату) и не должна быть связана с текущим процессом.

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

Я помещаю это здесь в основном для форматирования кода; код ниже работает для меня в той же ситуации при тех же условиях в моем проекте. Я не уверен, что это помогло бы, так как вы прямо упомянули, что пробовали подобный подход, но, поскольку в OP нет кода, с которым я могу сравнивать, мы идем.

Процесс, запускающий задачи, должен реализовать эти два handle_info/2 обратных вызова:

@doc false
# Task finished {#Reference<0.0.1.6335>, :ok}
def handle_info({_pid, _payload}, state),
  do: {:noreply, state}

@doc false
def handle_info({:DOWN, _ref, :process, _pid, :normal}, state),
  do: {:noreply, state}

При желании вы можете явно обработать последнее для других возвращаемых состояний, кроме :normal.


init не подходит для размещения Task.async/1, потому что init/1 является обратным вызовом, который вызывается из процесса, который запускает пользовательский DynamicSupervisor. Этот процесс будет получать info сообщений обратно (см. Ваш отчет об ошибках DynamicSupervisor не реализует обработчики .)

Ниже должно работать (при условии, что оба соответствующих handle_info/2 реализованы):

def start_link(arg) do
  with link <- DynamicSupervisor.start_link(...) do
    Task.async(...)
    link
  end
end

@impl true
def init(args) do
  DynamicSupervisor.init(args)
end
...