根据Erlang / OTP手册,如果我使用supervisor:start_child
将一个孩子添加到主管并且主管崩溃,则该孩子将不会自动重启。
(http://www.erlang.org/doc/design_principles/sup_princ.html#id73986)
是否有一个简单的解决方法,或者我是否必须以某种方式手动保存动态添加的子项并自行管理重新启动? (我的主管上面有一位主管,所以这是可能的,虽然不是很优雅。)
答案 0 :(得分:4)
您的主管是与其他人一样的流程,区别在于它们是系统流程(所有trap_exit
业务)。当它停止时它持有的内部状态随之而来 - 噗!
这是一件好事
主管死亡的恢复与死亡工人的恢复相同(毕竟,主管是另一位主管的工人)。您可能遇到的情况是监督树的结构与您的需求并不完全一致。如果你的主管去世需要工作继续存在,那么这些任务比你放置它们更接近程序的崩溃核心 - 这意味着它们应该是链条上面的东西的孩子或者(更有可能)你高估了它们对系统的重要性。
我开始关注确保流程持续存在的最常见原因是我承担了太多责任。每当我发现自己提出像#34这样的问题时,如果主管崩溃,我怎样才能确保孩子重新启动?#34;我停下来几分钟,仔细考虑为什么我问这个问题 - 这个总是引导我发现一个架构问题(并且修复它总是偶然地使系统的其他部分更多地做出更多其他问题明智的)。
现实生活中的例子:
在业务服务器中,有一个最初只是客户端连接的流程模块"。它发展成为管理与客户端的网络连接,内部Erlang值与外部协议值之间的转换,以及表示客户端在系统内的存在(存在,审计活动,授权,聊天等)。由于审计日志,我开始想知道和你一样:如果sup死了,我怎么能关闭客户端触及的东西等等?
然后发生了明显烦人的事情:从多个设备同时登录成为一项要求。当存在多个相同的"客户端"等时,多设备登录很奇怪(而不是单个客户端进程使用多个连接进程)。将这些任务分成不同的进程(不仅仅是模块)大大简化了事情,使状态恢复结构更加明显和清晰。
<强>附录强>
OP询问&#34;那么为什么静态和动态儿童在这方面存在差异?&#34;好问题。为什么做我们有静态子定义,动态监督命令,如supervisor:start_child/2
和supervisor:delete_child/2
和那些奇怪的simple_one_for_one
主管?
关键在于您的使用案例。让我们说我有一个游戏服务器需要总是有一个大厅可供使用,这样玩家就可以登录,聊天,查看军械库网站,用noob问题涂抹论坛和反开发者咆哮并且通常以其他方式浪费时间,这些方式仅与实际游戏有外围关系。我们从不希望在一个崩溃中立即将它们全部关闭,但也许我们希望能够告诉不同的运行服务在网络上监听或停止接受按需连接。然而,实际的游戏领域存在于他们自己的监督树的独立分支中 - 如果其中一个发生故障,我们不希望它带走其他一切,我们当然不想失去整个集群。
那么我们将如何构建呢?所有基本服务都将直接写入超级用户树的子定义 - 除非我们手动导致它,否则没有动态。每当我们启动系统时,它们就会弹出。因为我们可能有任意多个游戏领域,虽然领域定义在内部结构化为一个大多数静态定义的监督树,但每个领域级主管都是一个管理所有领域的simple_one_for_one主管的子代(所以如果那个主管失败那么POOF!大家都回到了大厅,可能很生气。可以根据我们的命令,设置文件或db数据或这些的组合来启动领域。
但是,延迟外部网络服务的启动可能是一件好事。启动系统时,我们可能会有一些重要的启动任务,并且无论如何都可能必须在集群中的不同节点上启动侦听器。作为避免直接通过网络连接对系统施加压力的一种方法,让我们有时间检查系统或运行测试,并有机会将系统设置为我们可能希望的某种特定模式(基准测试,测试,锦标赛或其他)延迟外部网络服务的启动。也就是说,我们强迫系统等待我们发送的命令,然后才能打开未洗过的群众的狂欢门。我们可以通过一些简单的调用将命令包装起来,我们可以从shell或网络(例如waste_of_youth:tempt_souls(Node, Port, Cert)
)访问,但是由于这是一系列supervisor:start_child/2
调用会发生什么 - 和那些是动态的。
那么如果网络服务经理死了会怎么样? POOF连接!在我们告诉他们之前,他们不会再次出现(不仅仅是活动连接,而是听众 - 可能已经死亡,独立于活动连接,取决于主管崩溃),因为系统是这样设计的。但是,如果这是一个问题,我们可以做任何事情来缓解这种情况。我们可以有一个过程,它的工作是了解和监视某些特定服务的最后状态,如外部网络 - 如果它意外地改变,则自己启动呼叫。但这通常不是您想要的 - 大多数情况下,当您需要自动重新启动服务时,您希望在启动时将永久服务的静态定义读入系统。
上面我提到了不同的模式,我们可能希望将服务器置于启动状态。将子定义与其余代码分开是很方便的,这样当我告诉它&#34;从游戏测试模式开始时#34;它加载了一些不同的主管定义(除非我们搞乱它,否则会坚持下去)。如果我告诉它&#34;从生产模式开始&#34;也许我们加载包含静态定义的永久网络服务处理程序的子定义。每个场合都有一组主管定义 - 通过这种方式,您可以轻松创建服务配置文件。这些动态管理程序命令允许您在服务状态之间手动切换,或将该转换过程委派给您在代码中某处定义的命令。