[erlang-questions] gen_server loop pattern

Nathaniel Waisbrot nathaniel@REDACTED
Fri Dec 4 18:24:24 CET 2015


I've been writing worker-processes that are mostly non-interactive as
gen_servers.

It looks something like this (skipping the boring bits, but I can include a
full example if this is unclear):


```
-module(fetcher).
-behavior(gen_server).

init(State) ->
  gen_server:cast(?MODULE, start),
  {ok, State}.

handle_cast(start, State) ->
  reschedule(State),
  {noreply, State};
handle_cast(loop, State) ->
  {Work, State1} = pull_from_queue(State),
  worker_pool:task(Work),
  reschedule(State1),
  {noreply, State1};
handle_cast({checkpoint, CheckpointData}, State) ->
  State1 = do_checkpoint(CheckpointData, State),
  {noreply, State1}.

reschedule(State) ->
  timer:apply_after(State#state.delay_ms, gen_server, cast, [?MODULE,
loop]).
```

It feels like I ought to use some other pattern, but I don't know what.

There's a few reasons that I've chosen gen_server:

* It's easy. The gen_server behavior is simple and I've already written
plenty of them.
* I can hook it easily to get some simple debug capability. I often add a
    ```
    handle_call(get_state, _From, State) -> {reply, State, State}.
    ```
* Likewise, I can pause and restart the worker by writing a few very simple
handle_* functions.
* The "checkpoint" message is used to send a checkpoint request to all
workers and then record a safe spot in the queue once I get a reply back
from all of them. This doesn't have to be in the `fetcher` module, but once
it's already a gen_server it seems easy to wedge it in.


Is there a better way to do this?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20151204/d56d505e/attachment.htm>


More information about the erlang-questions mailing list