在大多数项目中都会有一些计划任务(cron调度),当数量过大时,对于DevOps同学来讲就是个梦,管理迁移都不方便.
为了解决这个问题,济南IT培训准备用PHP开发一个调度程序实现管理计划任务,让它变成某项目的一部分.这样,crontab中的任务只有1个.
于是,我开发了一个事件计划模块,可以视为Google/Apple的简化版本.为存储关于重复事件的日期和规则,我使用了iCalendar格式(RFC 5545),该格式允许在一行内描述重复事件的时间,同时也照顾一周中的几天,几个月,重复次数等.以下是几个例子:
FREQ = WEEKLY; BYDAY = SU, WE - Weekly on Saturday and Wednesday
FREQ = MONTHLY; COUNT = 5 - Every month, five times
FREQ = YEARLY; INTERVAL = 2; BYMONTH = 1; BYDAY = SU - Every second year on every Saturday of January
我们看到,这种日期标准比cron描述的日期更灵活,更适合用它描述重复事件的规则.
为了使用iCalendar格式,我很幸运地找到一个很棒的第三方库:
https://github.com/simshaun/recurr .
有了一个RRULE(重复规则)的工具,开发应用就变得更简单,只需要写几个自己的计划和运行任务的类.
下面我们开始.
安装库:
composer require hutnikau/job-scheduler
计划和启动任务:
代表任务的类是: \Scheduler\Job\Job
要创建它的实例,您需要一个重复规则(RRULE)和一个可调用类型的实例:
$startTime = new \DateTime('2017-12-12 20:00:00');
$rule = new \Scheduler\Job\RRule('FREQ=MONTHLY;COUNT=5', $startTime); //run monthly, at 20:00:00 starting from the 12th of December 2017, 5 times
$job = new \Scheduler\Job\Job($rule, function () {
//do something
});
或者,使用\Scheduler\Job\ Job:: createFromString () :
$job = \Scheduler\Job\Job::createFromString(
'FREQ=MONTHLY;COUNT=5', //Recurrence rule
'2018-02-28T21:00:00', //Start date
function() {}, //Callback
'Asia/Shanghai' //Timezone. If $timezone is omitted, the current timezone will be used
);
请你不要设置忘记时区.强烈建议始终明确指定它们(不仅在使用此第三方库时),以避免不同机房时的时区问题!
接着,我们将任务添加到计划中:
$scheduler = new \Scheduler\Scheduler() $scheduler->addJob($job);
还可以将任务数组传递给构造方法:
$scheduler = new \Scheduler\Scheduler([ $job, //more jobs here ])
现在,启动计划任务:
$jobRunner = new \Scheduler\JobRunner\JobRunner();
$from = new \DateTime('2017-12-12 20:00:00');
$to = new \DateTime('2017-12-12 20:10:00');
$reports = $jobRunner->run($scheduler, $from, $to, true);
在此示例中,将执行为指定时间段(10分钟)计划的全部任务.
所以,我们只需要一个运行cron任务作业.
也可以省略参数$以便执行所有任务,从$开始直到当前时间.最后一个参数确定任务是否完成,其执行时间恰好落在边界值(示例中的'2017-12-12 20:00:00'和'2017-12-12 20:10:00')以上).
当使用cron启动调度程序时,我建议您保存最后一次运行的时间,并在下一次运行时将它传递给$从参数中增加1秒钟,因为cron的精度并不完美,并且有可能跳过任何任务或执行2次.
$jobRunner->run (...) 返回已完成任务的结果数组( \Scheduler\Action\Report类型的对象的数组).
\Scheduler\Action\Report { /* Methods */ public mixed getReport ( void ) public Action getAction ( void ) public string getType ( void ) }
通过调用\Scheduler\Action\Report::getReport()方法 ,我们可以取得执行后可调用(由其返回的值)的结果.
如果在执行任务期间抛出例外,\Scheduler\Action\Report:: getReport() 也会返回相同的异常.
方法\Scheduler\Action\Report::getAction()将返回类型为\Scheduler\Action\ActionInterface 的实例,该实例描述所采取的操作.通过使用它,你可以找出处理任务的时间或获得任务行为本身.
还值得注意的是,如果一个计划任务必须被执行多次(例如,如果RRULE中使用了MINUTELY间隔,并且$from和$to之间的差值在JobRunner中传输10分钟),那么该操作将会多次执行.
这个库体积比较小,希望对大家会有用.
更多济南IT培训相关咨询,请扫描下方二维码