DynamicSupervisor启动时启动工作程序

时间:2018-06-29 10:46:01

标签: elixir

我已经实现了一个DynamicSupervisor,可以处理使用Process.send_after/3来以一定时间精度发送推送通知的工作程序。

在某些情况下,例如当我发布不具有热交换功能的新版本时,我想保留所有尚未在DETS中完成的工作程序的记录,以及当DynamicSupervisor开始以相同的状态再次创建所有这些工作程序时,保存在DETS中。

我知道DynamicSupervisor从一开始就不支持工人,我应该实施start_child来开始新的工人,但是不知道如何将DynamicSupervisor的起点与这些工作人员在同一模块上的开始。

我尝试了不同的方法,但是没有成功(Task.asyncProcess.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}

:okstart_lost_children/0返回的结果。

如果我实现了handle_info/2,那么它什么也收不到。

2 个答案:

答案 0 :(得分:1)

我把它放在这里主要是为了代码格式化;下面的代码在我的项目中相同条件下的相同情况下对我有效。我不确定这是否会有所帮助,因为您已经明确提到您已经尝试过使用此方法进行排序,但是由于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

答案 1 :(得分:0)

Task.async/1启动必须等待的任务。开发人员最终必须调用Task.await/2Task.yield/2

尝试Task.start/1-仅当任务用于副作用(即对返回的结果不感兴趣)且不应该将其链接到当前过程时使用。