ROR的rake程序,用来调度任务脚本,可以很方便地在任务开始、结束、发生错误时插入hook,从而实现Job监控的目的。PHP没有像rake这样的程序来调度任务,所以下面自己写一个。
目录结构:
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。使用方式如下:
php wake.php test a b c
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(); ?>
得到以下结果,可以见到已经记录了运行时间:
---- 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的运行信息,方便统计分析。