erlang 为什么gen_server会超时

ny6fqffe  于 2022-12-08  发布在  Erlang
关注(0)|答案(3)|浏览(247)

I am trying to figure out why my gen_server crashes with a timeout since i am treating all possible cases:

module(wk).
-behaviour(gen_server).
-compile(export_all).

-record(state,{
    limit,
    count=0,
    toSend
}).
start_link(ToSend,Limit)->
   gen_server:start_link(?MODULE, {ToSend,Limit}, []).


init({ToSend,Limit})->
    State=#state{toSend=ToSend,limit=Limit},
    {ok,State}.

handle_call({process,Message},From,State)->
    {reply,{processed,os:timestamp()},State};
handle_call(Message,From,State)->
    self() ! {from_call,Message},
    {noreply,State}.
handle_cast(Message,State=#state{count=C})->
    self() ! {from_cast,Message},
    {noreply,State}.

handle_info(Message,State=#state{count=C,limit=L,toSend=T})->
    io:format("inside handle_info"),
    T! {badrequest,Message},
    Ret=if C>L -> {stop,State};
           _ ->{noreply,State#state{count=C+1}}
        end,
    Ret.

As you can see this server can handles a number of limit unknown messages , and as well as cast messages. Now my problem is with the handle_call :

  • If i send a message that fits the first case its ok and it replies back
  • When i send an unknown message using gen_server:call(S,xx) for example, i get a timeout error :

exception exit: {timeout,{gen_server,call,[<0.102.0>,33]}} in function gen_server:call/2 (gen_server.erl, line 215)
Why is my server timing out ? I can see that after handle_call it enters into handle_info but why does it crash ?
Usage:

{ok,Y}=wk:start_link(self(),3).
 gen_server:cast(Y,some_message).  % works limit times and then crashes as expected
 Y ! some_message % works limit times and then crashes as expected
 gen_server:call(Y,some_message) % gets inside handle_info , since i get the io message, then times out
zpjtge22

zpjtge221#

为什么我的服务器超时?
从gen_server:call()文档中:

call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply

通过发送请求并等待***直到收到答复或发生超时,***对gen_server进程的ServerRef进行*同步调用。
...
...
Timeout是一个大于零的整数,指定等待答复的毫秒数,或表示无限期等待的原子无穷大。默认值为5000。如果在指定时间内没有收到答复,则函数调用失败。
因为您选择在handle_call()函数中返回{noreply...},所以gen_server:call()无法返回,并在5秒后超时。您需要手动调用gen_server:reply/2(在另一个进程中),以便在超时前向客户端发送回复。

fnvucqvd

fnvucqvd2#

这里发生了一些事情。
您正在从GenServer内部向self()发送消息,这些消息将被发送到GenServer。这些消息需要在handle_info块中处理,我没有看到该块的实现,因此在这一点上,所有内容都被视为一个坏请求。
第二,通过状态中的Pid/Name将消息发送回调用者/发送者,这对于异步操作来说是很好的,只要你用{reply,“processing call”,State}这样的语句回复调用即可,因为你使用了noreply,调用就超时了,正如已经声明的那样。通常,你不会想使用一个马上返回一些东西的调用,但是如果您需要确认进程得到了作业并且正在处理它,那么这可能是一个很好的责任移交机制。否则,如果它是一个同步调用,那么使用gen_server:reply而不是T!Message语法,但是您必须区别对待调用和强制转换。
祝你好运

gr8qqesn

gr8qqesn3#

超时的是客户端。一旦它调用了gen_server:call/2的第二个子句,客户端仍然在等待响应,而响应永远不会被发回。

相关问题