一个网站要能正常运转起来,定时任务是必不可少的。要知道定时任务程序是否正确执行,要么每天去看日志文件,要么让监控程序帮你盯着它们。
ROR的rake程序,用来调度任务
脚本,可以很方便地在任务开始、结束、发生
错误时插入hook,从而实现Job监控的目的。PHP没有像rake这样的程序来调度任务,所以下面自己写一个。
目录结构:
class="yaml">
jobs
|--tasks
| |-test.php
|--wake.php
其中jobs/tasks/test.php的内容如下:
<?php
print_r($argv);
?>
假设当前目录在jobs下,所有的 job 脚本存放在tasks文件夹下,如果要执行tasks/test.php,通常是这么执行的:
php tasks/test.php a b c
结果如下:
Array
(
[0] => tasks/test.php
[1] => a
[2] => b
[3] => c
)
现在我们要对这个job进行监控,需要记录它开始运行的时间,结束运行的时间,运行时发生的错误(如果有)以及抛出的
异常(如果有),并且不能对现有的job脚本做太多的修改。wake.php就是本文的主角,它作为任务脚本的调度器,完成以上的需求。ROR中调度任务的程序叫rake,cakephp中console命名叫bake,我这里叫wake好了,唤醒的意思,意指唤醒具体的job。
wake.php内容:
<?php
/**
* @author lorienliu
*
* 启动Job,监控Job运行时发生的错误以及抛出的异常,记录开始和结束时间。
*/
//参数处理
array_shift($argv);
if (count($argv) == 0) {
exit;
}
$job_name = $argv[0];
$job_file_path = dirname(__FILE__) . '/tasks/' . $job_name . '.php';
// 处理错误
function error_handler($errno, $errstr, $errfile, $errline){
error_job($errno, $errstr, $errfile, $errline);
}
function start_job() {
//do something before job start
global $job_name;
echo "\n---- " . date("Y-m-d H:i:s") . " job start : " . $job_name . " ----\n";
}
//结束Job,可以在具体Job中调用,实现程序正常终止
function end_job() {
//do something after job ended
global $job_name;
echo "\n---- " . date("Y-m-d H:i:s") . " job end : " . $job_name ." ----\n";
exit;
}
function error_job($errno = 0, $errstr = '', $errfile = '', $errline = '') {
//do something when error occurs
global $job_name;
echo "\n----error occurs: ----\n";
echo "Message : $errstr\n";
echo "File : $errfile\n";
echo "Line : $errline\n\n";
exit;
}
set_error_handler('error_handler');
start_job();
try {
require_once $job_file_path;
} catch (Exception $e) {
error_job($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
}
end_job();
?>
使用方式如下:
php wake.php test a b c
得到以下结果,可以见到已经记录了运行时间:
---- 2013-06-08 02:36:02 job start : test ----
Array
(
[0] => test
[1] => a
[2] => b
[3] => c
)
---- 2013-06-08 02:36:02 job end : test ----
修改tasks/test.php内容,抛出异常:
<?php
print_r($argv);
throw new Exception("A custom exception");
?>
运行结果:
---- 2013-06-08 02:38:14 job start : test ----
Array
(
[0] => test
[1] => a
[2] => b
[3] => c
)
----error occurs: ----
Message : A custom exception
File : /home/gavin/www/butterfly/app/jobs/tasks/test.php
Line : 3
修改tasks/test.php内容,使得发生错误,这里引入一个不存在的文件:
<?php
print_r($argv);
require_once dirname(__FILE__) . '/abc.php';
?>
结果如下:
---- 2013-06-08 02:43:49 job start : test ----
Array
(
[0] => test
[1] => a
[2] => b
[3] => c
)
----error occurs: ----
Message : require_once(/home/gavin/www/butterfly/app/jobs/tasks/abc.php): failed to open stream: No such file or directory
File : /home/gavin/www/butterfly/app/jobs/tasks/test.php
Line : 3
可以见到,无论异常或者错误,wake.php都能够捕获。关键在于用try catch来处理异常,用set_error_handler来处理错误。这里有几个hook,start_job, end_job, error_job,可以在这些hook中添加某些操作,记录这些job的运行信息,方便统计分析。