Erlang 主管动态更改重启强度

Erlang supervisor dynamic change to restart intensity

我的问题是,除了发布升级场景之外,是否可以修改已经 运行 主管的重启强度阈值,如果可以,如何修改?

以前从来没有出现过,但是运行一个最初没有children的主管,所以另一个进程通过主管children启动:start_child/2,所以我的晚餐 init/1 是这样的:

init([]) ->
    RestartSt = {simple_one_for_one, 10, 10},
    ChSpec = [foo, {foo,start_link,[]}, transient, 1000, worker, [foo]}],
    {ok, {RestartSt, ChSpec}}.

supervisor启动时,children的可能数量未知;当然它可以从 10 到 10,000 或更多变化很大。

比如 20 的重启强度对于 10 次 children 来说足够了,但是对于 10,000 次 children 我希望能够增加它...并随着children 由于正常终止而掉线。

一个解决方案是嵌套你的主管。但主要问题是你想通过这种重启强度实现什么。当你想杀死主管时的强度需要表明一些非常错误的事情,例如。所需资源意外不可用。

没有 API 可以做到这一点,所以我相信你坚持使用升级方法,除非你想通过 [=28= 向 OTP 团队提出新的 API ] 提供包含代码更改、新测试和文档更改的完整补丁。

还有一种非常肮脏的 hack 方法可以做到这一点,它涉及操纵内部主管状态,因此我绝对不会推荐用于生产系统的东西,但我认为它仍然很有趣。 A supervisor stores restart intensity in its internal loop state. You can see this state by calling sys:get_state/1,2 on a supervisor process. For example, here's the state of a supervisor in the Yaws web server:

1> rr(supervisor).
[child,state]
2> sys:get_state(yaws_sup).
#state{name = {local,yaws_sup},
       strategy = one_for_all,
       children = [#child{pid = <0.67.0>,name = yaws_sup_restarts,
                          mfargs = {yaws_sup_restarts,start_link,[]},
                          restart_type = transient,shutdown = infinity,
                          child_type = supervisor,
                          modules = [yaws_sup_restarts]},
                   #child{pid = <0.42.0>,name = yaws_server,
                          mfargs = {yaws_server,start_link,
                                                [{env,true,false,false,false,false,false,"default"}]},
                          restart_type = permanent,shutdown = 120000,
                          child_type = worker,
                          modules = [yaws_server]},
                   #child{pid = <0.39.0>,name = yaws_trace,
                          mfargs = {yaws_trace,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_trace]},
                   #child{pid = <0.36.0>,name = yaws_log,
                          mfargs = {yaws_log,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_log]}],
       dynamics = undefined,intensity = 0,period = 1,restarts = [],
       module = yaws_sup,args = []}

初始的 rr 命令从 supervisor 中检索记录定义,因此当我们从 yaws_sup 中获取状态时我们可以看到字段名称,否则我们只会得到一个完整的元组匿名值。

在这种情况下,检索到的状态显示强度为 0。我们可以使用 sys:replace_state/2,3:

更改它
3> sys:replace_state(yaws_sup, fun(S) -> S#state{intensity=2} end).
#state{name = {local,yaws_sup},
       strategy = one_for_all,
       children = [#child{pid = <0.67.0>,name = yaws_sup_restarts,
                          mfargs = {yaws_sup_restarts,start_link,[]},
                          restart_type = transient,shutdown = infinity,
                          child_type = supervisor,
                          modules = [yaws_sup_restarts]},
                   #child{pid = <0.42.0>,name = yaws_server,
                          mfargs = {yaws_server,start_link,
                                                [{env,true,false,false,false,false,false,"default"}]},
                          restart_type = permanent,shutdown = 120000,
                          child_type = worker,
                          modules = [yaws_server]},
                   #child{pid = <0.39.0>,name = yaws_trace,
                          mfargs = {yaws_trace,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_trace]},
                   #child{pid = <0.36.0>,name = yaws_log,
                          mfargs = {yaws_log,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_log]}],
       dynamics = undefined,intensity = 2,period = 1,restarts = [],
       module = yaws_sup,args = []}

我们 sys:replace_state/2 的第二个参数将状态记录作为参数并将其 intensity 字段更改为 2。sys:replace_state/2,3 函数 return 新状态,并且正如您在结果末尾附近看到的那样,intensity 现在是 2 而不是 0。

正如 sys:replace_state/2,3 文档所解释的那样,这些函数仅用于调试目的,因此我绝对不推荐在生产系统中使用它们来执行此操作。这里 replace_state 的第二个参数表明这种方法需要了解 supervisor 的内部状态记录的详细信息,我们通过 rr shell 命令在这里获得了这些信息,所以如果该记录发生变化,此代码可能会停止工作。更脆弱的是将 supervisor 状态记录视为元组并指望 intensity 字段处于特定元组位置,以便您可以更改其值。因此,如果你真的想要改变主管重启强度的功能,你最好在长长的 运行 中向 OTP 团队提议添加它;如果您要走那条路,我建议您先在 erlang-questions mailing list 上提出想法以评估兴趣。