监督者的子进程由child specifications列表定义,当监督者启动时,其子进程将按该列表顺序从左到右启动,监督者终止运行时,其子进程将按相反方向关闭,最后终止监督者自己。子进程列表定义如下:
child_spec() = {Id, StartFunc, Restart, Shutdown, Type, Modules}
Id = term()
StartFunc = {M, F, A}
M = F = atom()
A = [term()]
Restart = permanent | transient | temporary
Shutdown = brutal_kill | int()>=0 | infinity
Type = worker | supervisor
Modules = [Module] | dynamic
Module = atom()
其中Id是监督者内部标识该子进程的名称,StartFunc定义了启动该子进程所需调用的函数,这个启动函数必须创建并连接到一个子进程,然后返回{ok, Child}或{ok, Child, Info},Child是子进程的pid,Info会被监督者所忽略;如果子进程因某些原因未能启动可返回ignore;如果发生了错误也可以返回一个{error, Error}。
Restart定义了子进程何时将会被重启:
permanent:无论子进程因何终止都应被重启;
temporary:无须重启子进程;
transient:仅在子进程因非正常原因终止时才重启子进程。
Shutdown定义了子进程应被如何终止:
brutal_kill:使用exit(Child, kill)强制终止;
int()>=0:监督者调用exit(Child, shutdown)告知子进程终止并等待其终止信号,若超过指定时间尚未收到再调用exit(Child, kill)来强制终止;
infinity:如果子进程为一个子监督者,则应将超时时间设定为infinity,以让其有充足时间来终止其子监督树。
Type定义了子进程是一个监督者还是一个工作进程。
监督者对子进程的重启方式(Restart Strategy)有如下几种:
one_for_one:如果一个子进程终止了,则只需重启该子进程;
one_for_all:如果一个子进程终止了,所有其他子进程都将被终止,然后重启所有子进程;
rest_for_one:如果一个子进程终止了,则按启动顺序比其晚启动的其他子进程都将被终止,然后该子进程和被终止掉的其他子进程都会被重启;
simple_one_for_one:是one_for_one的简化版,该监督者的所有子进程都是动态加入的,并且每个子进程类型都相同,都运行一样的代码。
为了避免监督者陷入子进程被不停的终止-重启的死循环,每个监督者都有一个最大重启频度(maximum restart frequency),由参数MaxR和MaxT所决定,如果在MaxT秒内发生多于MaxR次子进程重启,则监督者会终止其所有子进程和它本身。
Callback Module
supervisor behaviour的回调模块僅包含一个回调函数init/1:
init(_Args) ->
{ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}
Starting a Supervisor
监督者通过调用函数supervisor:start_link/2来启动,如下:
supervisor:start_link(MODULE, []).
MODULE为该监督者的回调模块,第二个参数为传入到回调函数init/1里的参数。如果想为该监督者注册个名字,也可以用下面这个函数来启动:
supervisor:start_link({local, Name}, Module, Args) 或
supervisor:start_link({global, Name}, Module, Args)
启动后,监督者会调用回调模块里的init/1函数,并根据该函数的返回值启动其子进程,注意supervisor:start_link这函数不是异步的,要直到所有子进程都启动后才会返回。
Adding a Child Process
监督树可以是静态的,也可以是动态的,我们可以随时加入新的子进程到监督树中:
supervisor:start_child(Sup, ChildSpec)
其中Sup是监督者的pid或注册名,ChildSpec是一个子进程声明。动态增添的子进程和其他子进程一样,但若监督者死掉然后被重新启动后,所有动态添加的子进程都会丢失。
Stopping a Child Process
所有子进程无论动态静态,都可以按照关闭设置被停止运行:
supervisor:terminate_child(Sup, Id)
可用如下函数删除被停止运行的子进程的进程声明:
supervisor:delete_child(Sup, Id)
同样,监督者本身重启后,删除静态子进程的操作将失效。
0 意見