测品娱乐
您的当前位置:首页PHP简单实现不依赖于Unix系统Cron的定时任务

PHP简单实现不依赖于Unix系统Cron的定时任务

来源:测品娱乐
应用场景:很多时候,我们的客户端希望自行订制一些即时执行的简单定时任务,而这是unix系统的crontad实现起来比较困难的,这时候,这种情况下,杀鸡并不需要什么宰牛刀啊,只是一个简单的定时任务而已,有没有简单的办法可以实现呢?当然有!

下面,我们通过一些小技巧来实现定时任务的生成和控制。代码如下:

crontab_config.php:作为一个任务控制文件 * 您可以将这里看做是每一个任务生成时的数据库记录集合 */

return [ 's1' => [

'continue' => 1,//总开关 'expire' => 1800,//允许任务最大自主运行时间(s) 'start_time' => strtotime('2017-06-23 14:10:00'),//开始运行时间,这里用strtotime是为了更直观而已 'sleep_time' => 15,//脚本睡眠时间(s) 'time_limit' => 0,//设置当前进程运行时间(s),为0则无(计算量较大时) 'memory_limit' => '128M'//设置php.ini中运行内存的值(M),建议大于128M,小于2048M ], 's2' => [ 'continue' => 0, 'expire' => 3600, 'start_time' => strtotime('2017-06-23 08:30:00'), 'sleep_time' => 15, 'time_limit' => 30, 'memory_limit' => '128M' ] #...... ];

php_crontab.php:任务执行文件 //serial_no:作为一个获取控制脚本记录的一个索引 $serial_no = $_GET['serial_no'];

if ($config[$serial_no]['continue'] != 1) exit(); if (($config[$serial_no]['expire'] + $config[$serial_no]['start_time']) < time()) exit(); // 设置为0可以让程序无的执行下去 set_time_limit($config[$serial_no]['time_limit']);

// 设置内存,不建议大于2048M

ini_set('memory_limit', $config[$serial_no]['memory_limit']); $mainObj = new main();

$no = $_GET['no']?(intval($_GET['no'])+1):1; $mainObj->doSomething($no);//执行主程序

sleep($config[$serial_no]['sleep_time']);//睡眠

$url = \"http://localhost/php_crontab.php?serial_no={$serial_no}&no={$no}\"; //继续执行下一次脚本(接口的方式,方便断开连接) $mainObj->http_get($url, 1000); exit(); /*

* 主程序部分 */

class main {

/**

* @param int no 执行次数 */ public function doSomething($no){

}

$log = date('Y-m-d H:i:s').\" 这是第{$no}次执行\\r\\n\";

file_put_contents('./php_crontab.log', $log, FILE_APPEND); return true;

/**

* GET 请求

* @param string url 访问链接

* @param int time_out 等待响应超时时间(ms) * @return string content */

public function http_get($url, $time_out=2000) { $oCurl = curl_init();

if (stripos($url, \"https://\") !== FALSE) {

curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 }

curl_setopt($oCurl, CURLOPT_URL, $url);

curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1); //注意,毫秒超时一定要设置这个

curl_setopt($oCurl,CURLOPT_NOSIGNAL,1);

?>

//超时毫秒,cURL7.16.2中被加入。从PHP5.2.3起可使用

//如果接口超时响应,则断开与它的连接(远程接口将不受影响) curl_setopt($oCurl,CURLOPT_TIMEOUT_MS,$time_out); $sContent = curl_exec($oCurl); $aStatus = curl_getinfo($oCurl); curl_close($oCurl);

if (intval($aStatus[\"http_code\"]) == 200) { return $sContent; } else {

return false; } } }

现在,我们通过浏览器来访问:http://localhost/php_crontab.php?serial_no=s1 默认浏览在30s后会断开,但程序会按照crontab_config.php中s1的配置继续执行,直到1800s后会自动终止,运行之后,部分结果如下图:

可能很多小伙伴会有疑问:

1、为什么浏览器(browser)断开之后,程序会继续执行呢?

原因在于设置了ignore_user_abort(true),其可忽略客户端是否断开

2、是不是我们可以通过配置crontab_config.php的相关数组参数就可以控制脚本的执行和状态了

是的。在实际项目,我们的crontab_config.php中的数据可以是每次生成任务时,用户自行配置的记录,这样会更加灵活,如果有需要,还可以做成分布式的任务呢,那么,大量的计算就不再是问题啦

3、为什么要使用自定义的http_get()接口方式访问下一次的脚本呢,不可以使用file_get_contents直接访问吗?

当然可以使用file_get_contents;这里使用接口的方式是为了能够及时关闭本次超时

的响应,不需要作太长时间的等待,降低服务器压力,这样做,相对于直接使用

file_get_contents类的函数会更好一点

4、这个程序有什么缺点吗?

最大的缺点是,当链路不友好的时候,只要有一次接口请求没有到达服务端,那么,整

个任务就会被终止了。这时候,您可以通过进一步优化,写一些脚本来实时跟踪或者检测相应任务的状态,比如sokect就是一个不错的选择,当然,ajax轮询也可以,此处不再赘述,有兴趣的可以自行探讨一下php的socket部分

5、如果我想把定时任务设置成指定时间才开始执行的,可以吗?

当然可以。您只要简单地在Unix系统上再加上一个crontab任务定时执行就可以了,这个定时任务,您是用来检查和执行数据库中所有已生成但未执行的定时任务的,只要执行过一次的,咱们下次crontab查询的时候不再执行就可以了,因为一旦crontab触发一个自定义的任务之后,后面的就交由上面的程序去完成啦

因篇幅问题不能全部显示,请点此查看更多更全内容