[erlang-questions] Is using gen_server behaviour appropriate for his usecase?

Roman Gafiyatullin r.gafiyatullin@REDACTED
Fri Nov 30 11:43:49 CET 2012


Vineet,

Using standard OTP behaviours for handling processes is not a bad practice.
It helps to always have unified predictable behaviour of the processes you spawn.

  
I will just enumerate several examples hoping those would be helpful for you:
* process A queries process B for something:
 [in A]  
{ok, Result} = gen_server:call( B, {request, Something}, CallTimeout ).

* procerss A asks B to do something but does not expect any response on this action:
 [in A]  
ok = gen_server:cast( B, {ack, ID} ).

* process A queries B for some results.
 Yet the query cannot be satisfied but will be once some event will be reported to B

 [in A]
it_occurred = gen_server:call( B, i_will_wait_for_a_while, infinity ).

 [in B]
handle_call( i_will_wait_for_a_while, From, State = #s{ reply_queue = Q } ) ->
 {no_reply, State #s{reply_queue = queue:in( From , Q )} };
…
handle_cast( the_event_i_told_you_about,  State = #s{ reply_queue = Q }) ->
{ReplyTo, NewQ} = queue:out( Q ),
 _Ignored = gen_server:reply( ReplyTo, it_occured  ),
{no_reply, State #s{ reply_queue = NewQ }};
...
In this very case it's probably better to think about employing gen_fsm behaviour - to handle the states like probably 'starving', 'caught_up', 'lagging' etc…

* Say we are handling some named resources each with one process.
   A client code if wants to interact with the resource needs to get the pid of the process owning the resource.
   A client code knows the name of the resource only.

resource_owner.erl:
maybe_start_resource_owner( ResourceName ) ->
case catch supervisor:start_link( resource_owners_sup , { ResourceName }) of
{ ok, Pid } -> ok;
ignore -> ok
end.

init({ ResourceName }) ->
case catch gproc:add_local_name( {resource_owner, ResourceName} ) of
true ->
{ok, #s{ resource_name = ResourceName }};
_ ->
ignore
end.


client_code.erl:
get_owner_pid_by_resource_name( ResourceName ) ->
ok = resource_owner:maybe_start_resource_owner( ResourceName ),
{ResourceOwnerPid, _} = gproc:await( {n, l, {resource_owner, ResourceName} } ),
{ok, ResourceOwnerPid}.

The main moral here - use the standard behaviours when spawning your processes.  
The OTP team has solved most of the potential problems for you already :)

--
RG


On Friday, November 30, 2012 at 12:49 pm, Vineet Naik wrote:

> Hi Roman,
>  
> Thanks for replying.
>  
> I think gen_server pretty much fits my case. But I would like to
> know whether it's fine to use gen_server if the model is not
> strictly based on client-server message passing. Does Erlang have
> any thing like "abuse of the gen_server" anti-pattern :-) ?
>  
> Regards,
> Vineet
>  
>  
> On Fri, Nov 30, 2012 at 2:06 PM, Roman Gafiyatullin
> <r.gafiyatullin@REDACTED (mailto:r.gafiyatullin@REDACTED)> wrote:
> > Hi,
> >  
> > In most of the cases one shall not use "simple loop functions": raw process
> > cannot participate properly in the supervision tree.
> >  
> > If you need some new tricky specific model of behaving - better implement it
> > over gen_server.
> > For instance supervisor is a gen_server :)
> >  
> > If you need something more low level - use 'gen' module (see how gen_fsm is
> > implemented).
> >  
> > --
> > Regards
> > RG ( +375 33 602 5080, UTC+3 )
> >  
> > On Friday, November 30, 2012 at 11:25 am, Vineet Naik wrote:
> >  
> > Hello,
> >  
> > I am an Erlang newbie and trying to write a simple chat bot as an
> > XMPP external component. I am using exmpp library and following
> > along these tutorials[1]
> >  
> > So far I have one module `bot_server` that uses the gen_server
> > interface. Inside it's `handle_info` callback, incoming messages
> > from various client will be received. To handle and reply to the
> > these messages, I am thinking of spawning a "bot" process per
> > client. It will stay alive as long as the client is available
> > ie. when the client sends "unavailable" presence, it will die. I
> > also need to keep a list of all the alive bot processes in the
> > bot_server's state.
> >  
> > My question is, would it be appropriate to implement the bot as a
> > gen_server too considering that it needs to handle two calls, one
> > for handling incoming message (asynchronous) and second for
> > killing itself (synchronous)?
> >  
> > In general, when should one use gen_server and when should
> > one write a simple loop function?
> >  
> > [1] exmpp tutorials:
> > http://blog.process-one.net/scalable_xmpp_bots_with_erlang_and_exmpp_part_i/
> >  
> > Thanks,
> > Vineet
> > _______________________________________________
> > erlang-questions mailing list
> > erlang-questions@REDACTED (mailto:erlang-questions@REDACTED)
> > http://erlang.org/mailman/listinfo/erlang-questions
> >  
>  
>  
>  
>  
> --  
> Vineet Naik
>  
>  


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20121130/dcf1d830/attachment.htm>


More information about the erlang-questions mailing list