Почему gen_server получает тайм-аут - PullRequest
1 голос
/ 05 мая 2020

Я пытаюсь понять, почему мой gen_server вылетает с тайм-аутом, поскольку я лечу все возможные случаи:

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.

Как видите, этот сервер может обрабатывать несколько limit unknown сообщения, а также cast сообщений. Теперь моя проблема связана с handle_call:

  • Если я отправлю сообщение, которое соответствует первому случаю, все в порядке, и он отвечает
  • Когда я отправляю неизвестное сообщение используя, например, gen_server:call(S,xx), я получаю ошибку тайм-аута:

    исключение exit: {timeout, {gen_server, call, [<0.102.0>, 33]}} в функции gen_server: call / 2 (gen_server .erl, строка 215)

Почему у моего сервера истекло время ожидания? Я вижу, что после handle_call он входит в handle_info, но почему он треснет sh?

Использование:

{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

Ответы [ 2 ]

2 голосов
/ 05 мая 2020

Почему у моего сервера истекает время ожидания?

С gen_server: call () docs:

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

Делает a синхронный вызов к ServerRef процесса gen_server путем отправки запроса и ожидания, пока не придет ответ или не истечет время ожидания.
.. .
...

Тайм-аут - это целое число больше нуля, которое указывает, сколько миллисекунд ждать ответа, или сколько атома ждать бесконечно. По умолчанию 5000. Если ответ не получен в течение указанного времени, вызов функции завершается ошибкой.

Поскольку вы решили вернуть {noreply...} в своей handle_call() функции, gen_server:call() не может вернуться и истекает через 5 секунд. Вам необходимо вручную позвонить gen_server:reply/2 (в другом процессе), чтобы отправить ответ клиенту до истечения тайм-аута.

0 голосов
/ 06 мая 2020

Здесь происходит несколько вещей.

Вы отправляете сообщения на self () из GenServer, которые будут отправлены на GenServer. Эти сообщения должны обрабатываться в блоке handle_info, который я не вижу реализованным, поэтому на данный момент все рассматривается как неправильный запрос.

Во-вторых, вы отправляете сообщения обратно вызывающему / caster через его Pid / Name, который вы держите в состоянии, что нормально для asyn c ops, если вы отвечаете на вызовы с помощью чего-то вроде {reply, "processing call", State}, поскольку вы использовали noreply, ваши вызовы тайм-аут, как уже было сказано. Обычно вы не хотите использовать вызов, который что-то возвращает сразу, но если вам нужно подтверждение того, что процесс получил задание и работает над ним, это может быть хорошим механизмом передачи ответственности. В противном случае, если это должен быть синхронный вызов, используйте gen_server: reply вместо T! Синтаксис сообщения, но вам придется обрабатывать вызовы и преобразования по-разному.

Удачи

...