毫秒级定时任务

基于Swoole的毫秒定时器,封装的定时任务,取代LinuxCrontab

1.创建定时任务类。

  1. namespace App\Jobs\Timer;
  2. use App\Tasks\TestTask;
  3. use Swoole\Coroutine;
  4. use Hhxsv5\LaravelS\Swoole\Task\Task;
  5. use Hhxsv5\LaravelS\Swoole\Timer\CronJob;
  6. class TestCronJob extends CronJob
  7. {
  8. protected $i = 0;
  9. // !!! 定时任务的`interval`和`isImmediate`有两种配置方式(二选一):一是重载对应的方法,二是注册定时任务时传入参数。
  10. // --- 重载对应的方法来返回配置:开始
  11. public function interval()
  12. {
  13. return 1000;// 每1秒运行一次
  14. }
  15. public function isImmediate()
  16. {
  17. return false;// 是否立即执行第一次,false则等待间隔时间后执行第一次
  18. }
  19. // --- 重载对应的方法来返回配置:结束
  20. public function run()
  21. {
  22. \Log::info(__METHOD__, ['start', $this->i, microtime(true)]);
  23. // do something
  24. // sleep(1); // Swoole < 2.1
  25. Coroutine::sleep(1); // Swoole>=2.1 run()方法已自动创建了协程。
  26. $this->i++;
  27. \Log::info(__METHOD__, ['end', $this->i, microtime(true)]);
  28. if ($this->i >= 10) { // 运行10次后不再执行
  29. \Log::info(__METHOD__, ['stop', $this->i, microtime(true)]);
  30. $this->stop(); // 终止此定时任务,但restart/reload后会再次运行
  31. // CronJob中也可以投递Task,但不支持Task的finish()回调。
  32. // 注意:修改config/laravels.php,配置task_ipc_mode为1或2,参考 https://wiki.swoole.com/#/server/setting?id=task_ipc_mode
  33. $ret = Task::deliver(new TestTask('task data'));
  34. var_dump($ret);
  35. }
  36. // 此处抛出的异常会被上层捕获并记录到Swoole日志,开发者需要手动try/catch
  37. }
  38. }

2.注册定时任务类。

  1. // 在"config/laravels.php"注册定时任务类
  2. [
  3. // ...
  4. 'timer' => [
  5. 'enable' => true, // 启用Timer
  6. 'jobs' => [ // 注册的定时任务类列表
  7. // 启用LaravelScheduleJob来执行`php artisan schedule:run`,每分钟一次,替代Linux Crontab
  8. // \Hhxsv5\LaravelS\Illuminate\LaravelScheduleJob::class,
  9. // 两种配置参数的方式:
  10. // [\App\Jobs\Timer\TestCronJob::class, [1000, true]], // 注册时传入参数
  11. \App\Jobs\Timer\TestCronJob::class, // 重载对应的方法来返回参数
  12. ],
  13. 'max_wait_time' => 5, // Reload时最大等待时间
  14. // 打开全局定时器开关:当多实例部署时,确保只有一个实例运行定时任务,此功能依赖 Redis,具体请看 https://laravel.com/docs/7.x/redis
  15. 'global_lock' => false,
  16. 'global_lock_key' => config('app.name', 'Laravel'),
  17. ],
  18. // ...
  19. ];

3.注意在构建服务器集群时,会启动多个定时器,要确保只启动一个定期器,避免重复执行定时任务。

4.LaravelS v3.4.0开始支持热重启[Reload]定时器进程,LaravelS 在收到SIGUSR1信号后会等待max_wait_time(默认5)秒再结束进程,然后Manager进程会重新拉起定时器进程。

5.如果你仅需要用到分钟级的定时任务,建议启用Hhxsv5\LaravelS\Illuminate\LaravelScheduleJob来替代Linux Crontab,这样就可以沿用Laravel任务调度的编码习惯,配置Kernel即可。

  1. // app/Console/Kernel.php
  2. protected function schedule(Schedule $schedule)
  3. {
  4. // runInBackground()方法会新启子进程执行任务,这是异步的,不会影响其他任务的执行时机
  5. $schedule->command(TestCommand::class)->runInBackground()->everyMinute();
  6. }