9

我正在使用 OTP 主管行为来监督和重新启动子进程。但是,当孩子死后,我想以与崩溃前相同的状态重新启动它。

如果我编写自己的自定义主管,我可以收到 {EXIT,Pid,Reason} 消息并对其采取行动。但是,当使用 OTP 主管行为时,它全部由 OTP 管理,我无法控制它。我实现的唯一回调函数是 init。

在这种情况下有什么标准方法吗?如何自定义由 otp 主管动态重启的孩子的状态?如何使用 OTP 获取终止进程的 Pid?或者也许可以在终止之前获取孩子的状态,然后将孩子恢复到崩溃前的相同状态?

4

3 回答 3

2

可能以相同的状态重新启动不是一个好主意。可能是错误的状态导致进程崩溃,如果您以相同的状态重新启动,它将再次崩溃。但是如果你想要这个,请使用外部资源来保留它(如 ets 或 mnesia)。

于 2012-12-01T14:53:55.810 回答
0

在不知道你在做什么的任何细节的情况下,我可以想象一个世界,以下是有意义的:

  1. 主管创建一个 ETS 表并将表标识符传递给每个孩子
  2. 子进程启动,并根据子进程的某些相关属性,查阅 ETS 表以查找要加载的状态
  3. 每次孩子的状态发生变化时,它都会将其写入 ETS 表

因此,如果我有代表 Cobol 的 12 个部落的 12 个子进程,每个子进程将使用其名称作为 ETS 表的键,以查找前一个化身在启动时留下的状态。并且每个进程都会在其状态发生变化时更新表(再次使用其名称作为键)。

主管将自动重新启动一个被杀死的孩子,并且上面的步骤 2 将在孩子的 init 方法中执行。第 3 步将在孩子的 handle_call、handle_cast 和 handle_info 方法中处理(我正在对您的流程的性质做出一些假设)。有许多可通过主管使用的重启策略,如果需要,甚至可以重启兄弟姐妹。

希望这能给你一些想法。

于 2012-11-30T04:31:27.580 回答
0

我认为这种对 OTP 主管行为的自定义并不容易。OTP 主管的设计方式迫使我遵循一些严格的设计实践。在这种情况下,最重要的一点是主管除了监视其子代并在异常终止的情况下重新启动它们之外,不应该做任何其他事情。监督者中不应有额外的逻辑,以免在监督者中引入任何错误,这是监督树和容错的关键部分。

当孩子死亡时,我想以与崩溃前相同的状态重新启动它 - 这通常是不好的做法,因为孩子可能因为终止前的损坏状态而死亡,并在这种情况下以相同的状态重新启动它肯定会出问题

在这种情况下有什么标准方法吗? 在重新启动它们之前,在主管中自定义子项的状态,这违反了主管的良好设计实践。因此,这类任务通常以不同的方式完成,例如通过引入另一个进程,例如 gen_server,该进程将负责通过主管 (supervisor:start_child) 启动子进程并维护所有进程的监视器。这个额外的过程可以在开始新的孩子之前做任何需要的定制。

如何使用 OTP 获取终止进程的 Pid? - 在通过 supervisor:start_child 启动子进程的附加过程中,您可以监视它们,然后收听 DOWN 消息。例如,在 gen_server 的情况下,您将使用 handle_info 函数,如下所示:

handle_info({'DOWN', Ref, process, _Pid, _}, S) -> 
    handle_down_worker(Ref, _Pid, S).

或者也许可以在终止之前获取孩子的状态,然后将孩子恢复到崩溃前的相同状态? - 如果我错了,请纠正我,但我认为在 Erlang 中不可能与“DOWN”消息一起发送子进程在终止之前的状态。如果这可能,那么我可以只处理类似于 {DOWN, Pid, Reason, State} 的消息并以相同的状态或部分状态重新启动进程。但是,我在想.. 你怎么能保持突然死亡的孩子的状态,例如被 exit(Pid, kill) 杀死?我怀疑这是可能的。

于 2012-12-01T15:37:23.677 回答