【问题标题】:Does supervisor block calls while restarting children?重新启动孩子时主管会阻止呼叫吗?
【发布时间】:2011-07-26 00:25:58
【问题描述】:

我试图了解这里发生了什么:

我有一个主管在不触发MaxR, MaxT 机制的情况下循环重启一个客户端。客户端只是缓慢地崩溃,永远不会触发速率限制。

会有另一种机制使用supervisor:which_children/1delete_child/2, start_child/2 使子集适应现实(它对USB 设备的扫描试图找到每个设备一个监督子)。

这通常表现为速率限制的安全网,但奇怪的是,它看起来根本没有调用删除和启动子项的机制。

为了了解发生了什么,我从 shell 中调用了 supervisor:which_children/1,看起来调用只是阻塞并且永远不会返回。

是否会在主管忙于尝试重新启动孩子时阻止对主管的调用?

附录:

看起来崩溃发生在子启动期间:

=SUPERVISOR REPORT==== 29-Mar-2011::21:36:20 ===
     Supervisor: {local,gateway_sup}
     Context:    start_error
     Reason:     {'EXIT',{timeout,{gen_server,call,[<0.155.0>,late_init]}}}
     Offender:   [{pid,<0.76.0>},
              {name,gw_3_5},
              {mfa,{channel,start_link,
                            [[{gateways,[{left,108},{right,103}]}],
                             {3,5}]}},
              {restart_type,transient},
              {shutdown,10000},
              {child_type,worker}]

【问题讨论】:

  • 你是在孩子的start_link函数里做gen_server:call吗?
  • 是的,我愿意。我需要在 gen_server 已经运行后进行一些后期初始化。
  • 为什么不在init 函数中这样做呢?看来这里可能有死锁的风险……
  • @Adam:late_init 中的东西需要 gen_server 已经运行(需要 gen_server 的 pid)。我在这里看不到任何死锁的可能性(并且超时的原因是已知的)。你可以在这里看到代码ideone.com/KtM6N
  • 抛开你的问题,你应该可以在gen_server进程中运行self()来获得它自己的pid。

标签: erlang erlang-otp erlang-supervisor


【解决方案1】:

除了讨论之外,问题的答案是:

当重启一个在启动过程中失败的子进程时,监督者在它的进程内部循环(它在内部是一个 gen_server)不处理任何对它的 API 调用。

因此,如果将主管的速率限制配置为不会在子项的启动错误时触发,则尤其糟糕。在我的示例中,我的启动速度很慢(尤其是出错时)。

因此,如果主管永远循环尝试重新启动子进程,则无法对其进行任何调用...这通常很糟糕。

【讨论】:

  • 最好的办法是争取一个尽可能简单的初始化阶段,并在进程启动后完成其余的工作。这样做的好处是双重的,首先,监督者尽可能少地参与(并且不会被阻塞,正如您所发现的那样,有很多重启和长初始化阶段的情况),其次,该进程受到监督者的保护,从开始(如果后面的设置出现问题,由主管处理)。
  • 阿门!对于复杂的init 回调(启动其他进程、读取文件等),我有过一些非常不愉快的经历。
猜你喜欢
  • 2014-03-29
  • 2014-12-09
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2017-05-02
  • 2023-03-16
  • 2011-10-16
  • 1970-01-01
相关资源
最近更新 更多