更准确地说:
我有一个负责动态儿童数量的主管。我希望它在第一次添加和启动给定子项时使用不同的 init 函数,而不是稍后发生的所有重新启动。或者,如果进程可以发现它已重新启动,我可以使用相同的函数。
从技术上讲,有一些副作用可用于查明进程是否由其主管重新启动或者是否是第一次启动。例如,您可以检查进程的 pid 并将其与主管的 pid 进行比较。然而,这是丑陋的、容易出错的,并且不符合 OTP 原则。事实上,管理程序本身、应用程序或节点本身可能已重新启动。试图找出答案是徒劳的。
相反,遵循 OTP 原则,您必须确保受监督进程执行相同的任务,无论它们是第一次启动还是重新启动。这可以通过处理进程之间依赖关系的适当监督树来实现。
想要查明进程是否已启动或重新启动的典型原因是,当它们首次启动时,它们必须执行一些不需要在重新启动时重做的操作。最终,您需要确保在终止时撤消启动时需要完成的操作,以便您的进程在所有情况下都可以在启动时执行相同的操作。
例如,要做的可能是启动另一个进程(我们称之为 B),然后在启动时链接子进程和进程 B,然后子进程终止,B 也将终止(并且相互)。您必须将 B 进程的主管配置为不重新启动其子进程(即,将它们设置为临时进程)。
(根据下面第一条评论更新)
添加工厂只会使问题进一步恶化,但并不能完全解决问题。假设您有一家工厂负责创建子项。此过程可以保存子级的状态并在重新启动时恢复它们。为了实现这一目标,您将:
erlang:monitor/2。每当子进程终止时,工厂都会收到一条消息。然后它可以重新启动子进程并为其提供状态;请注意,为了提高内存效率,您应该在单独的消息中从工厂恢复进程的状态。事实上,如果您将保存的状态放入规范中,主管将维护一个副本。
您可能还想确保如果工厂倒闭,儿童也会死亡。为了实现这一点,您应该链接这两个进程。因此,erlang:monitor/2您可以通过将进程配置为捕获退出(使用 )来将工厂配置为接收 EXIT 消息,而不是使用erlang:process_flag/2。
然而,这并不能解决问题,因为工厂本身可能会异常终止。它将由其主管重新启动,并且如果没有适当的清理,所有状态都将丢失。因此,您需要确保在工厂终止时撤消在儿童启动时需要执行的操作。