Laravel子分钟间隔定时任务为何跳过下一分钟?
Laravel 10子分钟间隔定时任务跳过分钟的问题
问题背景
环境为Docker+docker-compose,Cron与Laravel容器分离部署,使用Laravel 10新增的子分钟间隔定时任务功能时出现异常。
配置信息
- Crontab配置:
* * * * * php /var/www/api/artisan schedule:run >> /var/www/api/storage/logs/cron.log 2>&1
\App\Console\Kernel.php代码:
<?php namespace App\Console; use App\Jobs\OneC\SyncChangesFrom1C; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Illuminate\Support\Facades\Log; class Kernel extends ConsoleKernel { protected function commands(): void { $this->load(__DIR__ . '/Commands'); require base_path('routes/console.php'); } protected function schedule(Schedule $schedule): void { Log::debug('SCHEDULE RUN'); $schedule->job(new SyncChangesFrom1C)->everyTenSeconds(); } }
- 队列任务
SyncChangesFrom1C的handle方法为空。
异常现象
- Laravel日志显示
SCHEDULE RUN每两分钟触发一次:
[2023-12-25 08:22:01] local.DEBUG: SCHEDULE RUN [2023-12-25 08:24:00] local.DEBUG: SCHEDULE RUN [2023-12-25 08:26:00] local.DEBUG: SCHEDULE RUN [2023-12-25 08:28:00] local.DEBUG: SCHEDULE RUN
- Cron日志显示任务仅在偶数分钟内按10秒间隔执行,奇数分钟无任务运行:
2023-12-25 08:26:00 Running [App\Jobs\OneC\SyncChangesFrom1C] .... 14ms DONE 2023-12-25 08:26:10 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 6ms DONE 2023-12-25 08:26:20 Running [App\Jobs\OneC\SyncChangesFrom1C] .... 10ms DONE 2023-12-25 08:26:30 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 5ms DONE 2023-12-25 08:26:41 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 3ms DONE 2023-12-25 08:26:51 Running [App\Jobs\OneC\SyncChangesFrom1C] .... 15ms DONE 2023-12-25 08:28:00 Running [App\Jobs\OneC\SyncChangesFrom1C] .... 39ms DONE 2023-12-25 08:28:10 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 3ms DONE 2023-12-25 08:28:21 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 2ms DONE 2023-12-25 08:28:31 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 2ms DONE 2023-12-25 08:28:41 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 5ms DONE 2023-12-25 08:28:51 Running [App\Jobs\OneC\SyncChangesFrom1C] ..... 2ms DONE
对比验证
将任务改为everyMinute()后,任务运行正常,每分钟执行一次。
问题原因
Laravel的子分钟间隔任务依赖schedule:run启动的常驻进程在当前分钟内持续触发任务,该进程会持有调度锁直到当前分钟结束后才释放。而Cron每分钟调用一次schedule:run,当奇数分钟的Cron调用触发时,前一次偶数分钟的schedule:run进程仍持有锁,导致新的进程无法启动,直到下一个偶数分钟锁释放后才能重新执行。
解决办法
放弃使用Cron每分钟调用schedule:run的方式,改用Laravel的调度守护进程schedule:work:
- 在Laravel容器中启动常驻进程:
php artisan schedule:work - 该进程会持续监听调度任务,自动处理子分钟间隔的触发逻辑,无需依赖Cron的每分钟调用。
更新:已在Laravel官方仓库提交相关Issue。
内容的提问来源于stack exchange,提问作者Alex Smirnov
相关产品推荐
相关产品推荐

