美好的一天,
我有一个 gen_server
进程,它定期执行一些长时间运行的状态更新任务
handle_info
:
handle_info(trigger, State) ->
NewState = some_long_running_task(),
erlang:send_after(?LOOP_TIME, self(), trigger),
{noreply, NewState}.
但是当这样的任务运行时,整个服务器将变得无响应,并且对它的任何调用都会导致整个服务器崩溃:
my_gen_server:status().
** exception exit: {timeout,{gen_server,call,[my_gen_server,status]}}
in function gen_server:call/2
如何避免 gen_server 被阻塞?
当有人在任何时候调用 my_gen_server:status()
时,结果应该类似于:
{确定,task_active}
最佳答案
在单独的进程中执行长时间运行的任务。让此进程通知 gen_server 其任务进度(即是否可以跟踪任务进度),或者让进程完成任务或失败,但至少通知 gen_server 任务结果。
让 gen_server 与执行此长时间运行任务的进程链接,并让 gen_server 知道 PID 或注册名称,以便在出现退出信号时,它可以将该重要进程的死亡与其余进程隔离开来。
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 e.t.c. erlang:send_after(?LOOP_TIME, self(), trigger), {noreply,NewState}. some_long_running_task(ServerState)-> ....do work ....return results
关于Erlang gen_server 具有长时间运行的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8879177/