如何使用Erlang OTP supervisor行为重新启动带有自定义状态的子进程?

9

我正在使用OTP监管行为来监管和重启子进程。但是当子进程死亡时,我希望能够以它崩溃前的相同状态重新启动它。

如果我编写自己的定制监管器,我可以接收 {EXIT,Pid,Reason} 消息并采取相应措施。然而,使用OTP监管行为时,一切都由OTP管理,我没有任何控制权。我只实现了一个init回调函数。

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


可能是重新启动Erlang进程并保留状态的重复问题。 - toraritte
3个回答

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

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)杀死该进程?我怀疑这是不可能的。

0

不知道你在做什么具体的事情,但我可以想象以下情况是有意义的:

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

因此,如果我有12个代表Cobol 12个部落的子进程,每个子进程都会使用自己的名称作为ETS表的键来查找之前的状态。每个进程在其状态更改时也会更新表(再次使用其名称作为键)。

如果一个子进程被杀死,主管将自动重新启动该子进程,并执行步骤2。步骤3将在子进程的handle_call、handle_cast和handle_info方法中处理(我对你的进程性质做了一些假设)。通过主管,还可以使用多种重启策略,甚至可以重启兄弟进程。

希望这能给你一些思路。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接