Подтвердить что ты не робот

Какой лучший способ сделать что-то периодически в Эрланге?

У меня есть процесс, который нужно выполнять каждую работу каждые пятнадцать секунд. В настоящее время я делаю это так:

    -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 ()
        }.

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

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

вместо

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

Как вы могли догадаться, я совершил эту ошибку несколько раз. Это неприятно, потому что, как только код обрабатывает это сообщение query_state_data, таймауты больше не генерируются, и весь сервер останавливается. (Я могу "дефибриллить" его вручную, получив оболочку на машине и отправив сообщение "тайм-аут" вручную, но... eww.)

Теперь я мог бы попытаться запомнить, чтобы всегда указывать этот необязательный параметр Timeout в моем значении Result. Но это не масштабируется: я когда-нибудь забуду, и снова буду смотреть на эту ошибку. Итак: какой лучший способ?

Я не думаю, что хочу написать фактический цикл, который работает вечно, и большую часть времени проводит спать; что противоречит духу ОТР.

4b9b3361

Ответ 1

Лучший способ:

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}.

Ответ 2

Используйте timer: send_interval/2. Например:.

-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}.

Ответ 3

Используйте модуль timer:)