使用lager和poolboy停止应用程序时出现奇怪的错误消息

Fre*_*d K 7 erlang

我使用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)

Pau*_*yot 9

您看到的错误实际上不是错误,而是由lager生成的错误报告.此报告似乎是由poolboy中的错误引起的.

你可以:

  • 修复错误并向poolboy开发人员提交补丁.
  • 安全地忽略该报告.
  • 在退出时手动终止您的工作人员.

停止OTP应用程序时应该发生的事情是监督树用于终止所有进程,最好是优雅地进行.这样做的默认方法是向监督过程发送一个shutdown信号,如果这在一段时间后不起作用,则要残酷地杀死它们.一切顺利,你永远不会得到任何报告.

有两个Erlang细微之处来理解这个bug:

  1. 进程可以链接,这意味着当一个进程异常终止(即有其他原因normal)时,所有链接的进程都会以相同的原因终止.这种原语是OTP监督的基础.
  2. 进程可以捕获退出信号(或陷阱出口),这意味着它接收退出信号作为常规消息而不是终止(包括normal不终止它,但排除kill将无条件终止它).

与陷阱出口相结合的链接通常用于监视进程终止,还有在监视进程终止时终止受监视进程的额外好处.例如,如果主管终止,其子女将被终止.monitor还存在不对称机制.

在这里,您的主管(实现test_sup行为)将被终止,原因shutdown应该是这样.主管行为实际上捕获了退出,当它收到shutdown信号时,它会尝试根据其关闭策略终止其子节点.在这里,您使用默认策略,即shutdown首次尝试向孩子发送信号.因此,您的主管将shutdown信号发送给其唯一的孩子.

Poolboy这里主要介绍它的魔力,和你的上司的孩子居然是gen_serverpoolboy回调模块.它应该关闭池并优雅地终止.

此模块链接到池主管,但也链接到工作人员.这个令人惊讶的实现选择可能是池(poolboy gen_server)的崩溃将终止工人.但是,这是bug的来源,非对称监视器可能更有意义.由于主管已经与poolboy相关联,因此gen_server终止该poolboy过程最终将导致工人终止.

与工人联系的结果是他们也得到了shutdown最初指向该poolboy过程的退出信号.他们被终止了.这种终止被工人主管认为是异常的(实施poolboy_sup回调),因为它本身并不发送信号.结果,主管报告关闭,这是由lager在这里记录的.

poolboy 陷阱退出的事实不会阻止shutdown信号的传播.当接收到信号时,该过程不会立即终止,但它会将其作为消息接收.gen_server拦截此消息,调用terminate/2回调函数然后终止shutdown,最终将信号传播到所有链接的进程.

如果避免链接到工作程序不是一种选择,修复此错误的方法是取消链接终止处理程序中的所有工作程序.