我使用poolboy创建了简单的应用程序,几乎是空工作者,但是当我停止应用程序时,我看到由lager打印的以下错误:
10:50:26.363 [error] Supervisor {<0.236.0>,poolboy_sup} had child test_worker started with test_worker:start_link([]) at undefined exit with reason shutdown in context shutdown_error
Run Code Online (Sandbox Code Playgroud)
导致此错误的原因是什么?
主管:
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
ChildSpecs = [pool_spec()],
{ok, {{one_for_one, 1000, 3600}, ChildSpecs}}.
pool_spec() ->
Name = test_pool,
PoolArgs = [{name, {local, Name}},
{worker_module, test_worker},
{size, 10},
{max_overflow, 20}],
poolboy:child_spec(Name, PoolArgs, []).
Run Code Online (Sandbox Code Playgroud)
工人:
-module(test_worker).
-behaviour(gen_server).
-behaviour(poolboy_worker).
-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
-record(state, {}).
start_link([]) ->
gen_server:start_link(?MODULE, [], []).
init([]) ->
{ok, #state{}}.
handle_call(_Request, _From, State) ->
{reply, _Reply = ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
Run Code Online (Sandbox Code Playgroud)
该应用程序的其余部分非常标准.
Erlang:R16B02
Poolboy:1.0.1
Lager:撰写问题时主人的最新版本(822062478a223313dce30e5a45e30a50a4b7dc4e)
您看到的错误实际上不是错误,而是由lager生成的错误报告.此报告似乎是由poolboy中的错误引起的.
你可以:
停止OTP应用程序时应该发生的事情是监督树用于终止所有进程,最好是优雅地进行.这样做的默认方法是向监督过程发送一个shutdown信号,如果这在一段时间后不起作用,则要残酷地杀死它们.一切顺利,你永远不会得到任何报告.
有两个Erlang细微之处来理解这个bug:
normal)时,所有链接的进程都会以相同的原因终止.这种原语是OTP监督的基础.normal不终止它,但排除kill将无条件终止它).与陷阱出口相结合的链接通常用于监视进程终止,还有在监视进程终止时终止受监视进程的额外好处.例如,如果主管终止,其子女将被终止.monitor还存在不对称机制.
在这里,您的主管(实现test_sup行为)将被终止,原因shutdown应该是这样.主管行为实际上捕获了退出,当它收到shutdown信号时,它会尝试根据其关闭策略终止其子节点.在这里,您使用默认策略,即shutdown首次尝试向孩子发送信号.因此,您的主管将shutdown信号发送给其唯一的孩子.
Poolboy这里主要介绍它的魔力,和你的上司的孩子居然是gen_server用poolboy回调模块.它应该关闭池并优雅地终止.
此模块链接到池主管,但也链接到工作人员.这个令人惊讶的实现选择可能是池(poolboy gen_server)的崩溃将终止工人.但是,这是bug的来源,非对称监视器可能更有意义.由于主管已经与poolboy相关联,因此gen_server终止该poolboy过程最终将导致工人终止.
与工人联系的结果是他们也得到了shutdown最初指向该poolboy过程的退出信号.他们被终止了.这种终止被工人主管认为是异常的(实施poolboy_sup回调),因为它本身并不发送信号.结果,主管报告关闭,这是由lager在这里记录的.
poolboy 陷阱退出的事实不会阻止shutdown信号的传播.当接收到信号时,该过程不会立即终止,但它会将其作为消息接收.gen_server拦截此消息,调用terminate/2回调函数然后终止shutdown,最终将信号传播到所有链接的进程.
如果避免链接到工作程序不是一种选择,修复此错误的方法是取消链接终止处理程序中的所有工作程序.