Pergunta

Eu tenho um processo que precisa fazer algum trabalho a cada quinze segundos. Atualmente estou fazendo isso como este:

    -behavior(gen_server).

    interval_milliseconds ()-> 15000.
    init()->
        {ok, 
         _State = FascinatingStateData,
         _TimeoutInterval = interval_milliseconds ()
        }.

    %% This gets called automatically as a result of our handlers
    %% including the optional _TimeoutInterval value in the returned
    %% Result
    handle_info(timeout, StateData)->
        {noreply, 
         _State = do_some_work(StateData),
          _TimeoutInterval = interval_milliseconds ()
        }.

Isso funciona, mas é extremamente frágil: se eu quero ensinar o meu servidor de uma nova mensagem, quando eu escrever qualquer nova função de manipulador, eu tenho que lembrar de incluir o opcional tempo limite de intervalo em seu valor de retorno. Isto é, dizer se eu estou lidando com uma chamada síncrona, eu preciso fazer isso:

    %% Someone wants to know our state; tell them
    handle_call(query_state_data, _From, StateData)->
        {reply, StateData, _NewStateData = whatever (), interval_milliseconds ()};

em vez de

    %% Someone wants to know our state; tell them
    handle_call(query_state_data, _From, StateData)->
        {reply, StateData, _NewStateData = whatever ()};

Como você pode imaginar, eu fiz isso muito confundir um número de vezes. É desagradável, porque uma vez que as alças de código que mensagem query_state_data, os tempos de espera já não ficam gerados, e toda a grinds servidor a um impasse. (Eu posso "defibrillate"-lo manualmente, obtendo um shell na máquina e enviar uma mensagem "timeout" a mão, mas ... eww.)

Agora, eu poderia tentar lembrar sempre especificar esse parâmetro Timeout opcional no meu valor do resultado. Mas isso não escala: eu vou esquecer um dia, e estará olhando para este erro novamente. Então: qual é a melhor maneira

Eu não acho que eu quero escrever um loop real que corre para sempre, e passa a maior parte de seu tempo dormindo; que parece um contra ao espírito do OTP.

Foi útil?

Solução

A melhor maneira é:

init([]) ->
  Timer = erlang:send_after(1, self(), check),
  {ok, Timer}.

handle_info(check, OldTimer) ->
  erlang:cancel_timer(OldTimer),
  do_task(),
  Timer = erlang:send_after(1000, self(), check),
  {noreply, Timer}.

Outras dicas

Use temporizador : send_interval / 2. Por exemplo:.

-behavior(gen_server).

interval_milliseconds()-> 15000.
init()->
    timer:send_interval(interval_milliseconds(), interval),
    {ok, FascinatingStateData}.

%% this clause will be called every 15 seconds
handle_info(interval, StateData)->
    State2 = do_some_work(StateData)
    {noreply, State2}.

Use a temporizador módulo:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top