123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- <?php
- namespace addons\crontab\controller;
- use addons\crontab\model\Crontab;
- use Cron\CronExpression;
- use fast\Http;
- use think\Controller;
- use think\Db;
- use think\Exception;
- use think\Log;
- /**
- * 定时任务接口
- *
- * 以Crontab方式每分钟定时执行,且只可以Cli方式运行
- * @internal
- */
- class Autotask extends Controller
- {
- /**
- * 初始化方法,最前且始终执行
- */
- public function _initialize()
- {
- // 只可以以cli方式执行
- if (!$this->request->isCli()) {
- $this->error('Autotask script only work at client!');
- }
- parent::_initialize();
- // 清除错误
- error_reporting(0);
- // 设置永不超时
- set_time_limit(0);
- }
- /**
- * 执行定时任务
- */
- public function index()
- {
- $withPcntl = false;
- $pool = null;
- $config = get_addon_config('crontab');
- $mode = $config['mode'] ?? 'pcntl';
- if ($mode == 'pcntl' && function_exists('pcntl_fork')) {
- $withPcntl = true;
- $pool = new \Jenner\SimpleFork\Pool();
- }
- $time = time();
- $logDir = LOG_PATH . 'crontab' . DS;
- if (!is_dir($logDir)) {
- mkdir($logDir, 0755);
- }
- //筛选未过期且未完成的任务
- $crontabList = Crontab::where('status', '=', 'normal')->order('weigh DESC,id DESC')->select();
- $execTime = time();
- foreach ($crontabList as $crontab) {
- $update = [];
- $execute = false;
- if ($time < $crontab['begintime']) {
- //任务未开始
- continue;
- }
- if ($crontab['maximums'] && $crontab['executes'] > $crontab['maximums']) {
- //任务已超过最大执行次数
- $update['status'] = 'completed';
- } else {
- if ($crontab['endtime'] > 0 && $time > $crontab['endtime']) {
- //任务已过期
- $update['status'] = 'expired';
- } else {
- //重复执行
- //如果未到执行时间则继续循环
- $cron = CronExpression::factory($crontab['schedule']);
- if (!$cron->isDue() || ($crontab['executetime'] && date("YmdHi", $execTime) === date("YmdHi", $crontab['executetime']))) {
- continue;
- }
- $execute = true;
- }
- }
- // 如果允许执行
- if ($execute) {
- $update['executetime'] = $time;
- $update['executes'] = $crontab['executes'] + 1;
- $update['status'] = ($crontab['maximums'] > 0 && $update['executes'] >= $crontab['maximums']) ? 'completed' : 'normal';
- }
- // 如果需要更新状态
- if (!$update) {
- continue;
- }
- // 更新状态
- $crontab->save($update);
- Db::connect()->close();
- // 将执行放在后面是为了避免超时导致多次执行
- if (!$execute) {
- continue;
- }
- $runnable = new \addons\crontab\library\CommandRunnable($crontab);
- if ($withPcntl) {
- $process = new \Jenner\SimpleFork\Process($runnable);
- $name = $crontab['title'];
- $pool->execute($process);
- } else {
- $runnable->run();
- }
- }
- if ($withPcntl && $pool) {
- $pool->wait();
- }
- return "Execute completed!\n";
- }
- }
|