[erlang-questions] gen_server aggregating calls/casts
Jonathan Leivent
jleivent@REDACTED
Tue Jul 9 00:16:37 CEST 2013
On 07/08/2013 04:30 PM, Robert Raschke wrote:
> A gen_server is there to handle a resource such that requests to that
> resource are handled sequentially. It sounds like that doesn't quite match
> your use case.
>
> What you describe appears a little bit odd. Say you receive a request, and
> now, before you handle it, you check if more of the same request type has
> come in, and if they have, you add them in your "send results to" set. Now
> what? Do you check again? Or are you satisfied you can actually do some
> work?
The server goes through longish periods when it is doing work (writing
and syncing requests to disk, communicating with other servers, etc.).
After these longish periods, it is very likely that many requests have
accumulated on its queue, along with other messages that are not
requests. I'd be satisfied if it could aggregate all requests that are
currently on the server's queue, but do so without having to first go
through the processing of the non-request messages that have also
accumulated on its queue. Then, batch process those aggregated requests
together - including writing/syncing them to disk together - with big
performance savings due to amortizing the expensive write/sync operation
(as well as reducing network overhead for the other parts of request
processing).
>
> Do you maybe want to memoize results? By adding results to your server
> state, you could reply to identical(?) requests via lookup, leaving the
> resource in peace.
It needs to service any requests it aggregates before servicing any
non-request message. Or, rather, that's true of the first request.
Said a better way: requests can be processed earlier than non-request
messages that arrive before those requests, but the opposite is not true.
So, if the server memoizes the requests, it has to process them as soon
as it encounters the first non-request message - even though there may
be many more requests later in its queue it could aggregate with the
earlier ones. Because earlier requests must be processed before later
non-requests.
Unless I memoize ALL messages, requests and non-requests - so that the
server delays handling any until it gets to a queue-empty state or times
out or something. That's possible, but it sounds like I'll have to
write my own gen_server-like infrastructure dispatch loop once I've
accumulated all those non-requests. I guess that's possible...
A separate aggregating gen_server might be easier and more modular.
Like this:
aggregator actual server
========== =============
doing busy work...
request --> memoize and forward --> forwarded request enqueued
request --> memoize
...
request --> memoize
... done busy work
see forwarded request
handle call <-- call aggregator
reply all and clear --> handle aggregated requests
I'll try both...
> Or do you require some kind of batching, only bothering the resource if
> enough interest is present? Maybe augmented with some kind of time limit?
> This would probably be a bit harder to implement.
Yes - such processing might be nice. Knowing how many requests can be
written/synced to disk in about the same time as a single request, for
instance, and knowing approximately how long such a write/sync takes.
Which will vary greatly based on available hardware and the underlying
OS, external demands on disk IO, etc. I'll leave all that for version 2...
-- Jonathan
More information about the erlang-questions
mailing list