这次我们来看下具体定时任务是什么实现的
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的超时机制固定时间后执行这次任务,然后计算下一个超时,完成循环