Supervisor.restart_child/2或Process.exit(pid,:kill)?

Ale*_*kin 7 elixir erlang-supervisor

我有一个监督树,为了简单起见,我们假设一个主管(S)持有一个W具有:one_for_one策略的工人().

在某些情况下,我需要重新初始化W,最简单的方法就是崩溃它.我有两种不同的选择:Process.exit/2和/或Supervisor.restart_child/2:

Process.exit(W, :kill)
Run Code Online (Sandbox Code Playgroud)

[{id, _, :worker, _}] = Supervisor.which_children(S)
Supervisor.terminate_child(S, w_id)
Supervisor.restart_child(S, w_id)
Run Code Online (Sandbox Code Playgroud)

由于后者存在,我想它可能会更好用,但我无法意识到使用它会带来什么好处.假设是策略:rest_for_one和许多孩子,前者将重新启动工人列表的整个尾部,而后者将仅重新启动此特定工作人员.我找不到任何合理的文档,既没有抓住代码库中的这种差异.

所以,问题是:当使用策略时:one_by_one,通过terminaterestart循环还是Process.exit(pid, :kill)足够了它是否有意义?

Nic*_*lov 3

除了工作人员在使用时对退出信号有发言权之外Process.exit/2,这可能与您的场景并不完全相关(尽管人们可能会挂钩退出信号陷阱所需的任何重新初始化以避免重新启动工作人员),这里有一些可能相关的内容。

方法A。当Process.exit(W, :kill)被调用时,会发生以下情况:

  1. 工作进程被终止
  2. 主管收到'EXIT'被解雇工人的信号
  3. Supervisor 调用restart_child/3它根据指定的重启策略执行此操作

非常瘦弱和刻薄。

方法B。使用另一种手动方法时,会发生以下情况:

  1. terminate_child/2最终打电话shutdown/2
  2. shutdown/2默认情况下,尝试正常关闭子进程,使其有机会释放任何系统资源
  3. 如果子进程在超时后没有退出,它将被杀死
  4. 由于子进程在关闭之前就断开了链接'EXIT',因此主管不会收到信号并且不会自动重新启动子进程
  5. 下一次调用,restart_child(S, w_id)重新启动子级,重用其规范并规避适当的重新启动策略

为了使方法 A适用,孩子们不得分配外部资源。对于one_for_one策略而言,这是一条不错的捷径,在其限制范围内很有用。使用其他策略,它会导致其他孩子的重新启动可能无用和/或昂贵。当约束不成问题时,这种方法可能是对稳定解决方案的合理优化。

方法 B是控制个别子进程重新启动的更通用方法。它确实涉及更复杂的逻辑,提供优雅的交换行为。它还允许在子进程终止和重新启动之间放置额外的逻辑。额外的好处是即使使用rest_for_oneone_for_all策略也可以精确地重新启动目标子项。在我看来,对于不断发展的应用程序来说,这是一个更好的选择,因为它不受特定约束的限制,可以更轻松地进行实施更改。