为什么在GenServer中启动Supervisor会导致进程重新启动行为出现问题?

问题描述

问题标题指出:

为什么在GenServer中启动Supervisor会导致进程重启行为出现问题?

我发现讨论here内容如下:

特别是:

  • “监督树提供的保证较少,因为该过程可能会退出,并且监督者不会终止其子级。”

  • “如果命名主管子级,则可能会导致问题,因为在树的更高位置(在其init / 1中调用start_link的进程上方)时,命名的子级可能仍然存在”

  • “您将丢失一些高级OTP功能,例如重新加载代码,因为通过遍历监督树发现了处理模块”

根本原因是什么?总的来说这是否成立?

参考文献

  1. Related code changes
  2. Github issue

解决方法

OTP(监督树)是建立在BEAM功能之上的,例如监视,链接,信号和捕获它们。

主管本身就是gen_servers,其唯一目的是监视/重新启动其孩子并以标准方式终止他们/使其死亡。如果您创建一个gen_server来产生主管,则意味着您处于该级别,而普通主管没有晋级。

让我们考虑一下这种OTP场景:

         P1 - Parent supervisor
         |
         G1 - GenServer
         |
         S1 - Children supervisor
         |
         C1 - Children worker

如果您有gen_server的监护人(G1)在所有孩子(S1)都终止之前因某种原因去世,则监护人会等待所有孩子退出后再终止自身生活重新启动gen_server(G1')。这将产生S1',然后产生S1'。

突然之间有多个S1和C1实例同时运行,这很可能是个问题。

关于上述代码重新加载问题,这意味着code_changed回调树触发器将在G1处停止(因为G1不会将其传播到S1),而不是不会加载代码。

TL; DR: 主管非常专业gen_servers。如果将常规gen_server放在监管树的中间而没有提供监管者提供的所有保证,则会丢失该子树中的一些OTP功能。