Question

I am getting a strange error report that makes me think some calls are being executed before the gen_server initialization.

Here is the init code:

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

Here is the handle_info that should initialize the resource.

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

the return value of data_store:get_resource(ResourceId) is the #resouce{} record, used to match all the handle_call methods.

The crash report with a function clause since the process is still not initialized.

=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: []

This should never happens if the handle_info timeout allways is called before any handle_call.

Does anyone knows why this is happening ?

Was it helpful?

Solution

Guaranteed? No. The timeout is a message like any other. If during the middle of the init function you receive a message from another process, you will likely process that message first.

That being said, the init function for OTP processes like gen_server is synchronous from the calling process, meaning that the process will have finished its init function by the time you receive the Pid, making it exceedingly difficult for another process to send a message to it before it has a chance to execute the timeout.

Of course, I would not recommend using a timeout for this behavior. It's less well-defined what will happen, because the process is more-or-less yielding when it returns from init, and timers in Erlang are not guaranteed to fire exactly on time (timer:sleep(5000) will sleep at least five seconds, not exactly five seconds). Instead, send a message to self(); this lets the process know immediately that it has work to do, as the message winds up in your mailbox before init returns.

OTHER TIPS

I assume you are doing this to keep the initialisation of the server short. Otherwise there is no real reason not to call your data_store:get_resource/1 function directly in init/1.

A "standard" way of doing this is to in init/1 just do a cast to yourself.

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

You KNOW this will be the first message processed as the Pid has not been returned so no-one else can have sent a message to the server.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top