3

我收到一个奇怪的错误报告,让我认为在 gen_server 初始化之前正在执行一些调用。

这是初始化代码:

init([ResourceId]) ->
    process_flag(trap_exit, true),
    {ok, {not_initialized, ResourceId}, 0}.

这是应该初始化资源的handle_info。

handle_info(timeout, {not_initialized, ResourceId}) ->
    Resource = data_store:get_resource(ResourceId),
    {noreply, Resource, ?CACHE_TIMEOUT};

data_store:get_resource(ResourceId) 的返回值为#resouce{} 记录,用于匹配所有的handle_call 方法。

带有函数子句的崩溃报告,因为进程仍未初始化。

=CRASH REPORT==== 1-Feb-2013::14:20:03 ===
crasher:
  initial call: gbanga_resources:init/1
  pid: <0.11772.0>  
  registered_name: []
  exception exit: {function_clause,
                      [{gbanga_resources,terminate,
                           [{function_clause,
                                [{gbanga_resources,handle_call,
                                     [get_resource,
                                      {<0.11658.0>,#Ref<0.0.0.240914>},
                                      {not_initialized,12697711}],
                                     [{file,"src/gbanga_resources.erl"},
                                      {line,120}]},
                                 {gen_server,handle_msg,5,
                                     [{file,"gen_server.erl"},{line,588}]},
                                 {proc_lib,init_p_do_apply,3,
                                     [{file,"proc_lib.erl"},{line,227}]}]},
                            {not_initialized,12697711}],
                           [{file,"src/gbanga_resources.erl"},{line,176}]},
                       {gen_server,terminate,6,
                           [{file,"gen_server.erl"},{line,722}]},
                       {proc_lib,init_p_do_apply,3,
                           [{file,"proc_lib.erl"},{line,227}]}]}
    in function  gen_server:terminate/6 (gen_server.erl, line 725)
  ancestors: [gbanga_resources_sup,gbanga_workers_sup,<0.92.0>]
  messages: [{'$gen_call',{<0.11638.0>,#Ref<0.0.0.240915>},get_resource},
                {'$gen_call',{<0.11633.0>,#Ref<0.0.0.240916>},get_resource}]
  links: [<0.6609.0>]
  dictionary: []

如果在任何句柄调用之前始终调用句柄信息超时,则永远不会发生这种情况。

有谁知道为什么会这样?

4

2 回答 2

3

保证?不,超时与其他消息一样。如果在 init 函数的中间您收到来自另一个进程的消息,您可能会首先处理该消息。

话虽如此,像 gen_server 这样的 OTP 进程的 init 函数与调用进程是同步的,这意味着该进程将在您收到 Pid 时完成其 init 函数,这使得另一个进程很难向它发送消息在它有机会执行超时之前。

当然,我不建议对这种行为使用超时。不太清楚会发生什么,因为进程在从 init 返回时或多或少会产生,并且 Erlang 中的计时器不能保证准确按时触发(timer:sleep(5000) 将至少休眠5 秒,不完全是五秒)。self()相反,向;发送消息 这让进程立即知道它有工作要做,因为消息在init 返回之前就在您的邮箱中结束了。

于 2013-02-01T16:05:17.087 回答
3

我假设您这样做是为了缩短服务器的初始化时间。否则没有真正的理由不data_store:get_resource/1直接在init/1.

这样做的“标准”方法是对自己init/1进行演员表。

init([ResourceId]) ->
    process_flag(trap_exit, true),
    gen_server:cast(self(), init_phase_2),                 %Must be a cast!
    {ok, {not_initialized, ResourceId}}.

handle_cast(init_phase_2, {not_initialized,ResourceId}) ->
    Resource = data_store:get_resource(ResourceId),
    {noreply, Resource}.

知道这将是处理的第一条消息,因为 Pid 尚未返回,因此没有其他人可以向服务器发送消息。

于 2013-02-01T17:59:21.897 回答