[erlang-questions] Reinserting a message into a gen_server's mailbox

Ryan Zezeski rzezeski@REDACTED
Wed Aug 11 04:33:41 CEST 2010


On Thu, Jul 29, 2010 at 11:15 AM, Juan Jose Comellas <juanjo@REDACTED>wrote:

> I have a situation where for one specific gen_server:call/2 invocation I
> have to perform an action that may take a few seconds (e.g. reading from a
> DB; reading from external files). I don't want to block the gen_server
> process while I do this, so I want to spawn a helper process that takes
> care
> of reading the data I need. The problem is that I can receive several
> gen_server:call/2 invocations that depend on this data being present at the
> same time and I don't want to have them fail because the data is not yet
> ready. I've thought of two ways of solving this problem:
>
>
>
I'm currently writing an application that needs similar behavior, i.e. high
request throughput on single gen_server, but the requests may take a long
time to service.  I approached the problem by creating a gen_server name
req_delegate (under a supervisor w/ one_for_one restart policy) whose sole
purpose in life is to spawn req_hdlr processes and kick them off.  This way
the only time spent in the gen_server is the time needed to create a
new process and send a msg to it.  The req_hdlr is a worker underneath a
supervisor (underneath the main supervisor) with a simple_one_for_one
restart policy.  When a new one is created it is given a reference to the
process that made the request and it uses this to msg back the result.  When
the req_hdlr is done it simply dies.

My req_delegate has a function that looks like this:

handle_cast({new_request, Req}, State) ->
    %% Start new req_hdlr to process request
    {ok, Pid} = supervisor:start_child(req_hdlr_sup, [Req]),
    %% Tell it to process the request
    req_hdlr:process(Pid),
    {noreply, State}.

The caller then waits for a response from the newly spawned req_hdlr worker.
 I wrote a library module to make this easier.

This has worked great for me so far.  However, the next thing I want to
address (as I think you hinted to as well) is how to only have one req_hdlr
do the work when there are multiple requests for the same data.  In my case,
I'm using this app as the engine behind a web application.  I want to be
able to take 10 concurrent requests for the same data, and perform the work
only once.  I haven't solved this yet, but I have some ideas.  One idea is
to normalize every request to an ID that represents what it's asking for.
 If the req_delegate notices there is already a request for a particular ID
then it can have the req_hdlr piggy back off the request that is already in
progress.

Anyways, I hope I'm making sense.  I'm still _very_ new to Erlang and trying
to learn.

-Ryan


More information about the erlang-questions mailing list