初学 Elixir, 我常常对 Supervisor 的概念感到疑惑. 没有Supervisor, 程序也能正常运行, 为什么还要加上这个东西呢? 原来, 这和 Erlang 的基本信条 —— “就让它崩溃” 有关, 在 Erlang 中, 是没有 try…rescue 这样的错误救援机制的. 取而代之的是 Supervisor 机制, Supervisor 是一个专门用来监督进程的进程, 每当它的名下有进程出错崩溃, Supervisor就会按照既定的策略重启进程.
我们将 Supervisor 名下的进程叫做子进程, 将由 Supervisor 和子进程所组成的监督网络称为 监督树. 有了监督树的帮助, 我们可以方便地构建一个高容错的应用.
这里要注意模块和进程的关系. 模块是函数的集合, 而类似 start_link
的函数可以创建进程,
那么, 如何在 phoenix 项目里使用 Supervisor 呢? ELixir 内置了两个模块: Supervisor 和 Supervisor.Spec.
Supervisor.Spec
我们可以这样设置 supervisor 名下的子进程:
import Supervisor.Spec
children = [
worker(MyWorker, [arg1, arg2, arg3]),
supervisor(MySupervisor, [arg1]) # 这个 supervisor 也是子进程
]
Supervisor.start_link(children, strategy: :one_for_one)
Supervisor
这是以模块的方式配置 supervisor, 它包含了 import Supervisor.Spec
:
defmodule MySupervisor do
use Supervisor
def start_link(arg) do
Supervisor.start_link(__MODULE__, arg) # 会调用 init 回调
end
def init(arg) do
children = [
worker(MyWorker, [arg], restart: :temporary)
]
supervise(children, strategy: :simple_one_for_one)
end
end
‘Supervisor.Spec`的主要函数
supervise(children, options)
会以tuple 的形式返回一个 supervisor配置.
supervisor(module, args, options \ [])
将给定的模块设置为一个 supervisor.
worker(module, args, options \ [])
将一个给定的模块定义为 worker.
Supervisor
的主要函数
count_children(supervisor)
返回一个清点子进程数的映射.delete_child(supervisor, child_id)
通过子进程的id 删除其配置信息.restart_child(supervisor, child_id)
通过 id 重启子进程.start_child(supervisor, child_spec_or_args)
动态添加子进程配置信息, 并启动它.start_link(children, options)
按给定的子进程启动一个 supervisor.start_link(module, arg, options \ [])
按给定的模块启动一个 supervisor .stop(supervisor, reason \ :normal, timeout \ :infinity)
停止 supervisor.terminate_child(supervisor, pid_or_child_id)
终止子进程.which_children(supervisor)
返回子进程列表.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。