3

更准确地说:

我有一个动态数量的孩子的主管。我希望它在第一次添加和启动给定子项时使用不同的 init 函数,而不是在以后发生的所有重新启动中。或者,如果进程可能发现它已重新启动,我可以使用相同的功能。

4

3 回答 3

1

从技术上讲,可以使用副作用来确定进程是否由其主管重新启动,或者它是否是第一次启动。例如,您可以检查进程的 pid 并将其与主管的 pid 进行比较。但是,这很丑陋,容易出错,并且与 OTP 原则不相符。实际上,主管本身可能已重新启动,或者应用程序或节点本身可能已重新启动。试图找出是徒劳的。

相反,遵循 OTP 原则,您必须确保受监督进程执行相同的任务,无论它们是第一次启动还是重新启动。这可以通过处理进程之间依赖关系的适当监督树来实现。

希望了解进程是否已启动或重新启动的典型原因是,当它们第一次启动时,它们必须做一些在重新启动时不需要重做的事情。最终,您需要确保在 start 时需要做的事情在 terminate 时被撤消,这样您的进程就可以在所有情况下在 start 时做同样的事情。

例如,要做的可能是启动另一个进程(我们称之为 B),然后在启动时将子进程和进程 B 链接起来,然后如果子进程终止,B 也将终止(并且反过来)。您必须将 B 进程的主管配置为不重新启动其子进程(即使它们成为临时的)。

(根据下面的第一条评论更新)

添加工厂只会进一步推动问题,但并不能完全解决问题。假设您有一个工厂负责创建孩子。这个过程可以保存孩子的状态并在重启时恢复它们。为此,您将:

  • 确保主管不会重启孩子(他们应该被指定为临时的);
  • 在创建孩子之后创建一个监视器erlang:monitor/2。每当孩子终止时,工厂都会收到一条消息。然后它可以重新启动子进程并为其提供状态;
  • 让孩子们定期向工厂发送所需的信息。

请注意,为了提高内存效率,您应该在单独的消息中恢复出厂时的进程状态。实际上,如果您将保存的状态放入规范中,主管将保留一份副本。

您可能还想确保如果工厂倒闭,孩子们也会死去。为此,您应该链接这两个进程。因此erlang:monitor/2,您可以通过将进程配置为陷阱退出(使用 )来配置工厂以接收 EXIT 消息,而不是使用erlang:process_flag/2

然而,这并不能解决问题,因为工厂本身可能会异常终止。如果没有适当的清理,它将由其主管重新启动,所有状态都将丢失。因此,您需要确保在工厂终止时撤消子项启动时需要执行的操作。

于 2013-09-13T10:21:06.527 回答
0

我认为你应该首先澄清一个进程为什么会死,然后正确重启的相关策略是什么(你没有提供关于这个的信息)。然后,如果这些进程终止是您的应用程序的正常行为(例如会话超时),我的意见是您应该尝试将可能死亡的任务与负责存储状态的任务分开。将信息保存在 ets、dets 或 mnesia 中也可能是相关的。但正如保罗所说,尽量坚持 OTP 原则。

于 2013-09-14T12:53:04.547 回答
0

受监督的流程是 OTP 流程。因此,您的主管正在启动像 gen_server 这样的 otp 进程。要查看进程何时重新启动,请创建自己的名称服务器,然后使用 gen_server:start_link({via, YourModule, Identifier}... 跟踪重新启动。

于 2016-06-24T02:24:28.917 回答