[erlang-questions] Message Loop in Gen_Server

Garrett Smith <>
Wed Apr 17 19:45:29 CEST 2013


On Wed, Apr 17, 2013 at 12:41 PM, Garrett Smith <> wrote:
> On Wed, Apr 17, 2013 at 12:33 PM, Lee Sylvester <> wrote:
>> Hey guys,
>>
>> So, I've hit a "best practice" conundrum in OTP; I have a server utilising gen_server for a RabbitMQ consumer.  In the init of that gen_server, I'm setting up a RabbitMQ connection, but I also need to start a loop.  My guess was that I shouldn't call this before init exits, as I was passing the Connection and Channel objects to state for handling elsewhere.  If I handle the loop in init, surely it will never return?
>>
>> To simplify what I'm saying (as I'm confusing myself here), here's my code:
>>
>> init([]) ->
>>     {ok, Connection} = amqp_connection:start(#amqp_params_network{ host="localhost" }),
>>     {ok, Channel} = amqp_connection:open_channel(Connection),
>>     amqp_channel:call(Channel, #'exchange.declare'{exchange = <<"user_msgs">>,
>>                                                    type = <<"direct">>}),
>>     #'queue.declare_ok'{queue = Queue} =
>>         amqp_channel:call(Channel, #'queue.declare'{exclusive = true}),
>>     State = {Channel, Connection},
>>     amqp_channel:call(Channel, #'queue.bind'{exchange = <<"user_msgs">>,
>>                                               routing_key = term_to_binary(node(self())),
>>                                               queue = Queue}),
>>     amqp_channel:subscribe(Channel, #'basic.consume'{queue = Queue,
>>         no_ack = true}, self()),
>>     receive
>>         #'basic.consume_ok'{} -> ok
>>     end,
>>     loop(Channel),
>>     {ok, State}.
>
> Definitely not in init/1 -- that blocks the caller to start_link.
>
>> Now, if I don't put the loop in my init, then how can I be sure that the loop is called every time the gen_server restarts?  Can someone please suggest the "right" way to call the loop in my gen_server?
>
> It's awkward, which is the point of e2_task -- see
> http://e2project.org if you're curious -- but this is how:
>
> init(Args) ->
>   % init here
>   {ok, State, 0}.
>
> handle_info(timeout, State) ->
>     loop().
>
> The 0 element in the init result will cause an immediate 'timeout'
> message to be sent to the process, resulting in a handle_info/2
> callback.

Incidentally, if this is a loop that runs for the life of the process,
it's easier to just run a function using proc_lib:

proc_lib:start_link(M, F, A)

See http://erlang.org/doc/man/proc_lib.html for details.

You can setup your rabbit client at the start of the loop and just
loop thereafter.

Garrett


More information about the erlang-questions mailing list