Erlang gen_server with years of work

Good day,

I have a gen_server process that periodically performs some lengthy handle_info state update handle_info :

 handle_info(trigger, State) -> NewState = some_long_running_task(), erlang:send_after(?LOOP_TIME, self(), trigger), {noreply, NewState}. 

But when such a task is launched, the whole server becomes unresponsive, and any call to it leads to the failure of the entire server:

 my_gen_server:status(). ** exception exit: {timeout,{gen_server,call,[my_gen_server,status]}} in function gen_server:call/2 

How can you avoid gen_server blocking? And when one call to my_gen_server:status() at any given time, the result should look something like this: {ok, task_active}

+7
source share
2 answers

complete a long-term task in a separate process. Let this process inform gen_server about its progress with the task (that is, if the progress of the task can be tracked) OR let the process complete the task or fail, but at least inform gen_server about the results of the task.

Let gen_server be associated with the process performing this long-term task, and let gen_server know the PID or registered name so that in case of output signals it can isolate the death of this important process from Rest.

  handle_info (trigger, State) ->
     Pid = spawn_link (? MODULE, some_long_running_task, [State]),
     NewState = save_pid (Pid, State),
     {noreply, NewState};
 handle_info ({'EXIT', SomePid, _}, State) ->
     case lookup_pid (State) == SomePid of
         false -> %% some other process
             {noreply, State};
         true ->
             %% our process has died
             %% what do we do now?
             %% spawn another one?
             %% thats your decision to take
             ....
             ....
             {noreply, State}
     end;
 handle_info ({finished, TaskResult}, State) ->
     ..... %% update state etc
     erlang: send_after (? LOOP_TIME, self (), trigger),
     {noreply, NewState}.

 some_long_running_task (ServerState) ->
     .... do work
     .... return results
+13
source

This call does not crash, but simply an exception that can be caught:

 status() -> try gen_server:call(my_gen_server, status) catch exit:{timeout,_} -> {ok, task_active} end. 

However, the call will remain in the server queue, and after it finishes processing the current message, it will send a response message: {ServerRef, Reply} , which should be dropped by the calling process.

The only way to avoid locking any process in Erlang (whether gen_server or not) is not to run locking tasks on it. Thus, another alternative may be to perform your lengthy tasks in another process that speaks only to your server, so no one cares about blocking it.

+5
source

All Articles