【发布时间】:2019-04-17 07:02:55
【问题描述】:
我正在尝试从受监督的工作进程中终止整个监督树。这是我的监督树:
+--------------------------+
| |
+--------+ Sup1: Dynamic Supervisor +---------+
| | | |
| +-------------+------------+ |
| | |
| | |
v v v
+------------------+ +------------------+ +------------------+
| | | | | |
| Job1: Supervisor | | Job2: Supervisor | | Job3: Supervisor |
| | | | | |
+------------------+ +-+-------- +---+--+ +------------------+
| |
| |
| |
| |
v v
+-------------------+ +--------------+
| | | |
| Progress Monitor: | | Work: Worker |
| Worker | | |
| | +--------------+
+-------------------+
流程生命周期:
-
Job通过以下方式启动:DynamicSupervisor.start_child(__MODULE__, spec) - 每个作业也是一个监督树:1 个主管(重启策略 -
one_for_one)-> 2 个工人 -
Progress Monitorworker 知道给定工作何时完成 - 工作完成后,
Progress Monitorworker 尝试终止整个工作监督树,方法是调用:DynamicSupervisor.terminate_child(__MODULE__, pid) -
Progress Monitor预计会在terminate回调中执行清理步骤 - 它正在捕获退出信号
问题和观察:
-
DynamicSupervisor.terminate_child是一个阻塞调用,这意味着它也等待所有子进程终止,包括调用进程 -Progress Monitor -
Progress Monitor处于死锁状态,无法终止。父supervisor发送:kill信号,不会触发terminate回调
快速解决方法:
-
从
Progress Monitorworker 异步调用DynamicSupervisor.terminate_child:spawn(fn -> DynamicSupervisor.terminate_child(__MODULE__, pid) end) -
为
Sup1: Dynamic Supervisor定义关闭策略:shutdown: 5_000它将最多等待 5 秒等待作业监督树终止,然后发送
shutdown退出信号。这将确保为Progress Monitor进程调用terminate回调。
对他们俩都不满意。
问题:
- 如何从工作进程触发监督树终止并避免死锁?
- 如果从工作人员处终止监督树不是最佳做法,那么推荐的方法是什么?
- 有什么建议可以重新设计监督树以使优雅终止更容易吗?
【问题讨论】:
-
在我看来
Progress Monitor是不必要的。你能解释为什么Worker不能简单地做它的事情然后以normal的原因终止吗?看来您可以为此目的使用Task.Supervisor。
标签: erlang elixir erlang-otp erlang-supervisor