Erlang gen_server处理超时

时间:2014-04-01 16:50:42

标签: erlang timeout gen-server

我必须实现erlang gen_server进程,它们可以存活数小时。但是超时后gen_server进程应该被杀死。这些过程是动态启动的,因此使用动态监督。想法是在进程init上使用timer:apply_after()。所以gen_server进程的init看起来就是那个

init(Time) -> 
   timer:apply_after(Time, my_supervisor, kill_child, [self()]),
   % do other init things
   ok.

我对erlang有点新意,所以问题是这种方法是好还是有一些缺点?有更好的解决方案吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

我会做一些不同的事情:

init([]) ->
    erlang:send_after(Time, self(), timeout_shutdown),
    {ok, #state{}}.

handle_info(timeout_shutdown, State) ->
    {stop, normal, State};
...

这样,该过程可以优雅地关闭自己,而不需要主管杀死它。更好的是,您可以在主管中将孩子声明为transient,因此它不会重新启动。

答案 1 :(得分:2)

您可能需要考虑使用erlang:send_after / 3并使用handle_info对gen_server中的消息做出反应:

  

使用erlang创建计时器:send_after / 3和erlang:start_timer / 3是   比使用计时器提供的计时器更有效   模块。计时器模块使用单独的进程来管理计时器,   如果许多进程创建,那么该进程很容易变得过载   并经常取消定时器(特别是在使用SMP仿真器时)。

     

定时器模块中不管理定时器的功能(例如   timer:tc / 3或timer:sleep / 1),不要调用timer-server进程和   因此是无害的。

http://www.erlang.org/doc/efficiency_guide/commoncaveats.html

答案 2 :(得分:0)

您可以尝试以下代码:进程worker1每秒关闭一次,进程worker2每两秒关闭一次。 您只需加载两个梁,然后在erl shell中运行super:start_link(). super:main().

这是supervosor:

-module(super).
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([stop/0]).
-export([main/]).
%% Supervisor callbacks
-export([init/1]).

-define(SERVER, ?MODULE).

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

init([]) ->
    RestartStrategy = simple_one_for_one,
    MaxRestarts = 1000,
    MaxSecondsBetweenRestarts = 3600,

    SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},

    Restart = permanent,
    Shutdown = 2000,
    Type = worker,

    AChild = {worker, {worker, start_link, []},
          Restart, Shutdown, Type, [worker]},
    {ok, {SupFlags, [AChild]}}.

main() ->
    add_worker(worker1, 1000),
    add_worker(worker2, 2000).

add_worker(WorkerName, Time) when is_atom(WorkerName)->
    supervisor:start_child(?SERVER, [WorkerName, Time]).
stop() ->
    exit(whereis(?SERVER), shutdown).

这是gen_server:

-module(worker).
-behaviour(gen_server).
%% API
-export([start_link/2]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).

-define(SERVER, ?MODULE). 

-record(state, {}).

start_link(WorkerName, Time) ->
    io:format("server: ~p start!~n", [WorkerName]),
    gen_server:start_link({local, WorkerName}, ?MODULE, [WorkerName, Time], []).

init([WorkerName, Time]) ->
    erlang:send_after(Time, self(), {WorkerName, timeout_shutdown}),
    {ok, #state{}}.


handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.


handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({WorkerName, timeout_shutdown}, State) ->
    io:format("server: ~p timeout_shutdown!~n", [WorkerName]),
    {stop, normal, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.