初学 Elixir, 我经常对 Supervisor 的概念感到疑惑. 没有Supervisor, 程序也能正常运行, 为何还要加上这个东西呢? 原来, 这和 Erlang 的基本信条 —— “就让它崩溃” 有关, 在 Erlang 中, 是没有 try…rescue 这样的错误救援机制的. 取而代之的是 Supervisor 机制, Supervisor 是一个专门用来监督进程的进程, 每当它的名下有进程出错崩溃, Supervisor就会按照既定的策略重启进程.网络
咱们将 Supervisor 名下的进程叫作子进程, 将由 Supervisor 和子进程所组成的监督网络称为 监督树. 有了监督树的帮助, 咱们能够方便地构建一个高容错的应用.函数
这里要注意模块和进程的关系. 模块是函数的集合, 而相似 start_link
的函数能够建立进程, rest
那么, 如何在 phoenix 项目里使用 Supervisor 呢? ELixir 内置了两个模块: Supervisor 和 Supervisor.Spec.code
Supervisor.Spec
咱们能够这样设置 supervisor 名下的子进程:orm
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
supervise(children, options)
会以tuple 的形式返回一个 supervisor配置. it
supervisor(module, args, options \ [])
将给定的模块设置为一个 supervisor.io
worker(module, args, options \ [])
将一个给定的模块定义为 worker.import
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)
返回子进程列表.module