我已经实现了一个DynamicSupervisor,可以处理使用Process.send_after/3
来以一定时间精度发送推送通知的工作程序。
在某些情况下,例如当我发布不具有热交换功能的新版本时,我想保留所有尚未在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
,那么它什么也收不到。
答案 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/2
或Task.yield/2
。
尝试Task.start/1
-仅当任务用于副作用(即对返回的结果不感兴趣)且不应该将其链接到当前过程时使用。