定时任务管理程序,子进程定期出现僵尸进程,附代码!

自己写的定时任务管理程序,隔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程序总出现卡死,猜测是他的问题,把他增加了详细日志,观察下

  • 用户名跟userid都可以登录的sql语句怎么写?
  • PHP MySQL 关于文章字段,内容分页的几个小问题?
  • thinkphp5模板能否指定某一个页面不显示该模板?
  • 公众号文章底部的小程序二维码如何统计?
  • 想问一下,近百张样式不同的Excel表导入获取数据的解决方案?
  • hosts文件失效
  • 请问匹配最后一个空格后的内容的正则表达式怎么写?
  • 怎样优化discuz提高网站速度
  • wordpress问题求助
  • Tp5+ajax返回数据后,处理json的问题
  • 实现计划任务方案分析和选择