主管。restart_child/2 或 Process.exit(pid, :kill)?

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

我有一个监督树,为了简单起见,假设一个监督者(S)持有一个工人(W),策略为:one_for_one

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

Process.exit(W, :kill)

[{id, _, :worker, _}] = Supervisor.which_children(S)
Supervisor.terminate_child(S, w_id)
Supervisor.restart_child(S, w_id)

既然后者存在,我想它可能会有更好的用处,但我不知道使用它有什么好处。假设是策略 :rest_for_one 和许多 children,前者将重启工人列表的整个尾巴,而后者只会重启这个特定的工人。我找不到任何合理的文档来说明代码库中的这种差异。

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

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

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

  1. 工作进程被终止
  2. supervisor receives 'EXIT' signal from terminated worker
  3. 主管调用restart_child/3,它根据指定的重启策略

非常苗条和刻薄。

方法 B。使用另一种手动方法会发生什么:

  1. terminate_child/2 结束调用 shutdown/2
  2. shutdown/2 默认情况下尝试正常关闭 child,让它有机会释放任何系统资源
  3. 如果child在超时后没有退出,它会被杀死
  4. 由于childgets unlinked之前被关闭,supervisor没有收到'EXIT'信号,不会自动重启child
  5. 下一次调用,restart_child(S, w_id) 重新启动 child 重用其规范并绕过适当的重启策略

要使方法A适用,children不得分配外部资源。使用 one_for_one 策略,它是一个不错的捷径,在其限制范围内很有用。对于其他策略,它可能会导致 and/or 昂贵地重新启动其他 children。当约束不是问题时,这种方法可能是对稳定解决方案的合理优化。

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