作者 Karson

新增定时任务处理

修复一处常量在低版本时可能出现的BUG
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 {include file="common/meta" /} 4 {include file="common/meta" /}
5 </head> 5 </head>
6 6
7 - <body class="inside-header inside-aside {$Think.const.IS_DIALOG ? 'is-dialog' : ''}"> 7 + <body class="inside-header inside-aside {:defined(IS_DIALOG) && IS_DIALOG ? 'is-dialog' : ''}">
8 8
9 <div id="main" role="main"> 9 <div id="main" role="main">
10 <div class="tab-content tab-addtabs"> 10 <div class="tab-content tab-addtabs">
  1 +<?php
  2 +
  3 +namespace app\index\controller;
  4 +
  5 +use app\common\model\Crontab;
  6 +use fast\Date;
  7 +use fast\Http;
  8 +use think\Controller;
  9 +use think\Db;
  10 +use think\Exception;
  11 +use think\Log;
  12 +
  13 +/**
  14 + * 定时任务接口
  15 + *
  16 + * 以Crontab方式每分钟定时执行,且只可以Cli方式运行
  17 + * @internal
  18 + */
  19 +class Autotask extends Controller
  20 +{
  21 +
  22 + /**
  23 + * 初始化方法,最前且始终执行
  24 + */
  25 + public function _initialize()
  26 + {
  27 + // 只可以以cli方式执行
  28 + if (!$this->request->isCli())
  29 + $this->error('Autotask script only work at client!');
  30 +
  31 + parent::_initialize();
  32 +
  33 + // 清除错误
  34 + error_reporting(0);
  35 +
  36 + // 设置永不超时
  37 + set_time_limit(0);
  38 + }
  39 +
  40 + /**
  41 + * 执行定时任务
  42 + */
  43 + public function crontab()
  44 + {
  45 + $time = time();
  46 + $logDir = LOG_PATH . 'crontab/';
  47 + if (!is_dir($logDir))
  48 + {
  49 + mkdir($logDir);
  50 + }
  51 + //筛选未过期且未完成的任务
  52 + $crontabList = Crontab::where('status', '=', 'normal')->order('weigh desc,id desc')->select();
  53 + foreach ($crontabList as $crontab)
  54 + {
  55 + $update = [];
  56 + $execute = FALSE;
  57 + if ($time < $crontab['begintime'])
  58 + {
  59 + //任务未开始
  60 + continue;
  61 + }
  62 + if ($crontab['maximums'] && $crontab['executes'] > $crontab['maximums'])
  63 + {
  64 + //任务已超过最大执行次数
  65 + $update['status'] = 'finished';
  66 + }
  67 + else if ($crontab['endtime'] > 0 && $time > $crontab['endtime'])
  68 + {
  69 + //任务已过期
  70 + $update['status'] = 'expired';
  71 + }
  72 + else
  73 + {
  74 + //重复执行
  75 + //如果未到执行时间则继续循环
  76 + if (!Date::cron($crontab['schedule']))
  77 + continue;
  78 + $execute = TRUE;
  79 + }
  80 +
  81 + // 如果允许执行
  82 + if ($execute)
  83 + {
  84 + $update['executetime'] = $time;
  85 + $update['executes'] = $crontab['executes'] + 1;
  86 + $update['status'] = ($crontab['maximums'] > 0 && $update['executes'] >= $crontab['maximums']) ? 'finished' : 'normal';
  87 + }
  88 +
  89 + // 如果需要更新状态
  90 + if (!$update)
  91 + continue;
  92 + // 更新状态
  93 + $crontab->save($update);
  94 +
  95 + // 将执行放在后面是为了避免超时导致多次执行
  96 + if (!$execute)
  97 + continue;
  98 + try
  99 + {
  100 + if ($crontab['type'] == 'url')
  101 + {
  102 + if (substr($crontab['content'], 0, 1) == "/")
  103 + {
  104 + // 本地项目URL
  105 + exec('nohup php ' . ROOT_PATH . 'public/index.php ' . $crontab['content'] . ' >> ' . $logDir . date("Y-m-d") . '.log 2>&1 &');
  106 + }
  107 + else
  108 + {
  109 + // 远程异步调用URL
  110 + Http::sendAsyncRequest($crontab['content']);
  111 + }
  112 + }
  113 + else if ($crontab['type'] == 'sql')
  114 + {
  115 + // 执行SQL
  116 + Db::getPdo()->exec($crontab['content']);
  117 + }
  118 + else if ($crontab['type'] == 'shell')
  119 + {
  120 + // 执行Shell
  121 + exec('nohup php ' . $crontab['content'] . ' >> ' . $logDir . date("Y-m-d") . '.log 2>&1 &');
  122 + }
  123 + }
  124 + catch (Exception $e)
  125 + {
  126 + Log::record($e->getMessage());
  127 + }
  128 + }
  129 + return 'Execute completed!';
  130 + }
  131 +
  132 +}