尽力而为的 OTP 监督

Posted

技术标签:

【中文标题】尽力而为的 OTP 监督【英文标题】:Best-effort OTP supervision 【发布时间】:2018-01-31 10:42:27 【问题描述】:

我想做的是改变我的主管,尽最大努力让孩子们继续跑步,但如果他们的崩溃率超过强度,就放弃。这样,其余的孩子就可以继续奔跑。不过,现有的主管配置似乎不可能做到这一点,所以看起来我唯一的选择可能是实现我自己的主管,这样我就可以让它在收到EXIT 时以这种方式运行。

有没有办法在不编写自己的主管的情况下实现这样的自定义 OTP 主管行为?

【问题讨论】:

您能详细解释一下具体的用例吗?您所描述的听起来不像是主管没有满足您的需求,而更像是您可能正在尝试通过监督做一些有更好选择的事情。这听起来很像在init/1 期间尝试做一些容易失败的事情,导致进程在重新启动时很快崩溃。 所以我在这里从各种来源为内部监控工具提取服务遥测数据。我使用simple_one_for_one 监督并根据启动子项时传递的配置文件中的值动态创建这些子项。孩子属于gen_server,它会根据延迟消息定期处理请求,而在init 中唯一要做的就是将配置存储为状态并将初始延迟消息排队。这让我可以定期提取数据,每个工作人员都独立于其他工作人员。 【参考方案1】:

你也可以使用director,解决这个问题更灵活。

【讨论】:

【参考方案2】:

在我看来,你想要的是每个孩子都有一个单独的监督者,正如你所说,负责将其保持在一个限制范围内,并且作为上面的一层,只有一个监督者(一对一或simple-one-for-one),其孩子被标记为临时的,因此当其中一个放弃时,其余的继续运行。

【讨论】:

谢谢!这听起来正是我需要的!【参考方案3】:

您不能“扩展”Supervisor 以添加不同的监督行为,但您也不必从头开始。 :supervisor 模块本身是在 :gen_server 之上实现的,所以如果你确实需要某种自定义监督行为,我会参考 :supervisor 的源代码(你可以找到 here);它将为您提供构建基础,以避免您可能遇到的一些陷阱。

一旦我对您的用例有了更好的了解,我可以扩展我对替代解决方案的回答。正如我在评论中提到的,在我看来,您可能在init/1 的流程中做一些容易失败的事情; init/1 不是处理这些事情的地方,因为如果暂时无法成功执行该操作,您几乎肯定会破坏主管的最大重启强度。

例如,假设您有一个与数据库对话的进程,并且需要一个数据库连接;您不想在init/1 期间尝试连接到数据库。相反,您应该在初始化后获取连接(可能在首次使用时,或者通过立即使用Process.send_after(self(), :connect, 0) 向进程发送初始化后消息),如果连接失败,则向任何调用者返回类似:error, :database_unavailable 的内容,同时您尝试重新建立连接。使用这种方法进行设计将使您的监督树保持稳定,并将如何处理故障的决定推给可能对故障如何影响有更好信息的客户(即,如果他们重试操作,返回一个调用者出错、异常退出等)

【讨论】:

以上是关于尽力而为的 OTP 监督的主要内容,如果未能解决你的问题,请参考以下文章

OTP&ETS

您如何设计基于Erlang / OTP的分布式容错多核系统的架构?

每个主管有多少工人?

为啥有一个监督树而不是一个集中的监督者?

Erlang模块supervisor翻译

安装和激活Office 2019