更确切地说:
我有一个动态儿童数量的主管。我希望它在给定的孩子被添加并且第一次启动时使用不同的初始化函数,而不是在以后发生的所有重启。或者,我可以使用相同的功能,如果进程可以发现它已重新启动。
答案 0 :(得分:1)
从技术上讲,有副作用可用于查明进程是否由其主管重新启动,或者是否是第一次启动。例如,您可以检查流程的pid并将其与主管的pid进行比较。但是,这很难看,容易出错,与OTP原则不一致。实际上,主管本身可能已经重新启动,或者应用程序或节点本身。试图找出它是徒劳的。
相反,遵循OTP原则,您必须确保受监督的流程执行相同的任务,无论它们是第一次启动还是重新启动。这可以通过处理进程之间依赖关系的适当监督树来实现。
希望了解某个进程是否已启动或重新启动的典型原因是,当它们首次启动时,必须执行一些不需要在重新启动时重做的操作。最终,您需要确保在启动时需要完成的操作在终止时撤消,因此您的流程在所有情况下都可以在启动时执行相同操作。
例如,要做的可能是启动另一个进程(让我们称之为B),然后只是在启动时链接子进程和进程B,然后子进程终止,B也将终止(并且相互) 。您必须将B进程的主管配置为不重新启动其子进程(即使其临时)。
(根据以下第一条评论进行更新)
添加工厂只会进一步推动问题,但并未完全解决问题。假设您有一个负责创建孩子的工厂。此过程可以保存子项的状态并在重新启动时恢复它们。要做到这一点,你会:
erlang:monitor/2
创建子项后创建监视器。每当孩子终止时,工厂都会收到一条消息。然后它可以重新启动子项并为其提供状态; 请注意,为了提高内存效率,您应该在单独的消息中恢复出厂状态。实际上,如果您将保存的状态放在规范中,主管将保留一份副本。
如果工厂死亡,你也可能想确保孩子死亡。要实现这一点,您应该link这两个过程。因此,您可以将工厂配置为陷阱退出(使用erlang:monitor/2
),而不是使用erlang:process_flag/2
,您可以将工厂配置为接收EXIT消息。
然而,这并没有解决问题,因为工厂本身可能会异常终止。如果没有适当的清理,它将由其主管重新启动,所有州都会丢失。因此,当工厂终止时,您需要确保在子项启动时需要执行的操作已撤消。
答案 1 :(得分:0)
我认为你应该首先澄清一个进程为什么会死,然后正确重启的相关策略是什么(你不提供相关的信息)。 然后,如果应用程序的正常行为是这些进程终止(例如会话超时),我的意见是你应该尝试将可能死的任务与负责存储状态的任务分开。 将信息保存在ets,dets或mnesia中也可能是相关的。 但正如保罗所说,试图坚持OTP原则。
答案 2 :(得分:0)
监督流程是OTP流程。因此,您的主管正在启动像gen_server这样的otp进程。要查看进程何时重新启动,请创建自己的名称服务器,然后使用gen_server:start_link({via,YourModule,Identifier} ...来跟踪重新启动。