Erlcron 源码分析(3)

这次我们来看下具体定时任务是什么实现的


erlcron.erl模块

cron(Job) ->
    JobRef = make_ref(),
    ecrn_cron_sup:add_job(JobRef, Job).

erl_cron_sup.erl

add_job(JobRef, Task) ->
    {ok, _} = supervisor:start_child(?SERVER, [JobRef, Task]),
    JobRef.

%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================

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

    SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},

    Restart = transient,
    Shutdown = 2000,
    Type = worker,

    AChild = {ecrn_agent, {ecrn_agent, start_link, []},
              Restart, Shutdown, Type, [ecrn_agent]},

    {ok, {SupFlags, [AChild]}}.

很好,一个simple_one_for_one的启动策略,这里可以看出每定义一个任务系统会启动一个进程去处理这个任务,单个任务的处理会被扔给ecrn_agent.erl去处理,ecrn_agent.erl 针对每个任务调用ecrn_agent:start_link/2去启动一个gen_server进程。


ecrn_agent.erl

start_link(JobRef, Job) ->
    gen_server:start_link(?MODULE, [JobRef, Job], []).

init([JobRef, Job]) ->
    State = #state{job=Job,
                   alarm_ref=JobRef},
    {DateTime, Actual} = ecrn_control:datetime(),
    NewState = set_internal_time(State, DateTime, Actual),
    case until_next_milliseconds(NewState, Job) of
        {ok, Millis} when is_integer(Millis) ->
            ecrn_reg:register(JobRef, self()),
            {ok, NewState, Millis};
        {error, _}  ->
            {stop, normal}
    end.

这里针对每个任务的配置调用until_next_milliseconds(NewState, Job)计算出任务下次执行的超时时间,然后用gen_server的超时机制固定时间后执行这次任务,然后计算下一个超时,完成循环

你可能感兴趣的:(Erlcron 源码分析(3))