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

时间:2013-10-14 06:56:39

标签: 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

导致此错误的原因是什么?如何解决此问题?

监:

-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, []).

工人:

-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}.

应用程序的其余部分非常标准。

Erlang:R16B02

Poolboy:1.0.1

Lager:撰写问题时主人的最新版本(822062478a223313dce30e5a45e30a50a4b7dc4e)

2 个答案:

答案 0 :(得分:8)

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

你可以:

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

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

有两个Erlang细微之处可以理解这个错误:

  1. 进程可以是linked,这意味着当一个进程异常终止时(即使用normal以外的原因),所有链接的进程都会以相同的原因终止。这个原语是OTP监督的基础。
  2. 进程可以trap exit signals(或陷阱退出),这意味着它将接收退出信号作为常规消息而不是终止(包括不会终止它的normal ,但不包括将无条件终止它的kill
  3. 与陷阱退出相结合的链接通常用于监视进程终止,还有在监视进程终止时终止受监视进程的额外好处。例如,如果主管终止,其子女将被终止。还存在不对称的monitor机制。

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

    Poolboy在这里引入了它的魔力,你的主管的孩子实际上是一个gen_serverpoolboy回调模块。它应该关闭池并优雅地终止。

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

    链接到工作人员的后果是他们还获得shutdown退出信号,该信号最初被定向到poolboy进程。他们被终止了。工作人员的主管(实施poolboy_sup回调)认为此终止是异常的,因为它本身并不发送信号。因此,主管会报告关闭,此处由lager记录。

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

    如果无法选择link to workers,则修复此错误的方法是取消关联terminate handler中的所有工作人员。

答案 1 :(得分:1)

你如何停止申请?也许主管应该有一个停止/ 1功能?例如,见

http://www.erlang.org/doc/apps/kernel/application.html#stop-1