Autotask.php 3.9 KB

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