我试图在10秒计时器上更新我的进程状态。
-define(INTERVAL, 3000).
start_link() ->
gen_server:start_link(?MODULE, [], []).
action(Pid, Action) ->
gen_server:call(Pid, Action).
init([]) ->
erlang:send_after(?INTERVAL, self(), trigger),
{ok, temple:new()}.
我想做的就是打电话给这个
handle_call({fight}, _From, Temple) ->
NewTemple = temple:fight(Temple),
{reply, NewTemple, NewTemple};
所以我试试
handle_info(trigger, _State) ->
land:action(self(), {fight}),
erlang:send_after(?INTERVAL, self(), trigger);
但我得到
=ERROR REPORT==== 4-Dec-2016::19:00:35 ===
** Generic server <0.400.0> terminating
** Last message in was trigger
** When Server state == {{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[]}}},
[]}
** Reason for termination ==
** {function_clause,[{land,terminate,
[{timeout,{gen_server,call,[<0.400.0>,{fight}]}},
{{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[],[]}}},
[]}],
[{file,"src/land.erl"},{line,47}]}
答案 0 :(得分:1)
看来,对于land:action(self(), {fight})
,您尝试将call
发送到您当前处理trigger
消息的同一gen_server。两个重要的事实将解释为什么这不起作用:
call
始终等待返回结果。在处理trigger
消息时,您要对call
回复自己并等待自己处理{fight}
消息。但是,由于您正在处理trigger
消息,因此您永远不会收到{fight}
消息。你和你自己陷入了僵局。这就是你要暂停的原因。
P.S。发布SSCCE更有可能为您提供良好的答案。
答案 1 :(得分:0)
错误消息表示陆地服务器模块中没有terminate
子句,编译陆地服务器模块时应该有警告。
调用terminate
子句是因为在gen_server调用期间发生超时,参数(Pid = <0.400.0>, Message = {fight})
在land:action(self(), {fight}),
行调用。对gen_server的调用必须在最长时间内完成,默认为5000ms,你必须减少在战斗行动中花费的时间。
请注意,增加服务器超时并不是一个好主意,因为gen_server调用正在阻塞:在执行gen_server调用期间,不会处理任何新消息,并且在您的示例中,它也阻止执行handle_info(trigger, _State)
代码。
最后一点,子句handle_info(trigger, _State)
应该返回{noreply,NewState}
形式的元组,而最后一行erlang:send_after(?INTERVAL, self(), trigger);
返回一个计时器引用,你必须修改这一行。