自己写的定时任务管理程序,隔10多天就会出现一直执行的子进程(按理说执行最多10分钟,肯定执行完了),导致同一个定时任务不会再次执行,想请教下,代码写的哪里有问题啊?
[work@bank-api01 bmanage.jindanlicai.com]$ ps aux|grep crontab
work 19672 99.9 0.3 374396 30676 ? R Feb06 1240:58 省略,执行超过一天了!!
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Crontab extends CI_Controller
{
public function daemon()
{
if (!is_cli()) {
exit('请cli下运行');
}
$this->crontab_model->reset_crontab_status();//重置任务状态
while (TRUE) {
$this->crontab();
}
}
private function crontab()
{
$this->benchmark->mark('code_start');
//每5分钟更新一次任务列表
if (empty($this->crontab_list) || 0 == date('i') % 1) {
$this->crontab_list = $this->crontab_model->get_list();
}
foreach ($this->crontab_list as $crontab) {
$c_id = $crontab['c_id'];
$cron_time = $crontab['time'];
$command = $crontab['command'];
try {
$cron_start_time = $this->cronlib->parse($cron_time);//https://github.com/jkonieczny/PHP-Crontab/blob/master/Crontab.class.php
} catch (Exception $e) {
$this->_write_log('error,cron_time格式错误');
continue;
}
$current_minute_time = strtotime(date('YmdHi00'));
$next_minute_time = $current_minute_time + 60;
if ($cron_start_time >= $current_minute_time && $cron_start_time < $next_minute_time) {
$row = $this->crontab_model->get_by_cid($c_id);
if (strtotime($row['last_start_time']) >= $current_minute_time && strtotime($row['last_start_time']) < $next_minute_time) {
//$this->_write_log("id:{$c_id},command:{$command},当前分钟已经运行过一次了");
continue;
}
if ($row['status'] == Crontab_model::STATUS_DOING) {
$this->_write_log("id:{$c_id},command:{$command},运行中");
continue;
}
$this->_write_log("id:{$c_id},command:{$command},开始运行");
$this->_children_process($command, $c_id);
continue;
}
}
$this->benchmark->mark('code_end');
$exec_time = $this->benchmark->elapsed_time('code_start', 'code_end');
if ($exec_time >= 59) {
$this->_write_log("error,单次循环运行时间>59秒!");//测试100个任务,都是微妙级别
}
foreach ($this->children_process as $key => $pid) {
$res = pcntl_waitpid($pid, $status, WNOHANG);
if ($res == -1 || $res > 0) {
$this->_write_log("子进程:{$pid},捕获退出");
unset($this->children_process[$key]);
}
}
sleep(59 - $exec_time);
}
private function _children_process($command, $c_id)
{
$pid = pcntl_fork();
if ($pid == -1) {
$this->_write_log('error,can not fork');
die;
}
if ($pid) {
$this->children_process[] = $pid;
} else {
ini_set('max_execution_time', 1800);//最大执行时间30分钟
$children_pid = posix_getpid();
$this->_write_log("子进程:{$children_pid},运行");
//before执行
$start_time = date('Y-m-d H:i:s');
$this->crontab_model->update_by_cid($c_id, [
'status' => Crontab_model::STATUS_DOING,
'last_start_time' => $start_time,
]);
//执行
$stdout = shell_exec($command);
$this->_write_log("子进程:{$children_pid},运行结束");
die;
}
}
}
strace -p 出现
Process 19671 attached - interrupt to quit
fcntl(13, F_SETFL, O_RDWR|O_NONBLOCK) = 0
fcntl(13, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(13, F_SETFL, O_RDWR) = 0
fcntl(13, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(13, F_SETFL, O_RDWR|O_NONBLOCK) = 0
wait4(-1,
这类信息
因为只有一个crontab程序总出现卡死,猜测是他的问题,把他增加了详细日志,观察下