【问题标题】:How to check whether the process was restarted by supervisor?如何检查进程是否被主管重新启动?
【发布时间】:2013-09-17 02:32:30
【问题描述】:

更准确地说:

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

【问题讨论】:

  • 似乎无法获取有关进程重启的信息:进程状态是本地的(您不能使用它来存储重启计数),并且主管模块不提供此类功能。但是您可以使用单独的 process/ets-table/file 来存储所需的信息。

标签: erlang


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

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

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

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

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

      【讨论】:

      • 感谢您提供许多出色的见解,但似乎它们与我的案例并不完全相关。在过程寿命期间,它会获得某种(简单)状态。然后应该保留并在重新启动后恢复。 Sill,试图恢复全新的进程状态会导致死锁。原因:所有描述的进程都是由 gen_server 创建的,它作为它们的工厂工作。这也是修改其状态的过程。所以,调用层次是:sth -> factory (create process) -> supervisor (add child) -> child (init) -> factory (modify my state) = deadlock = timeout.
      • 我更新了响应以将工厂示例考虑在内。使用异步消息可以避免死锁。子进程可以在初始化处理程序中向自己发送一条异步消息(使用gen_server:cast(self(), Message)),相应的handle_cast 处理程序将从工厂获取状态。或者,如果主管永远不会重新启动子进程,则工厂可以在启动子进程后立即提供状态。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 1970-01-01
      相关资源
      最近更新 更多