The recurring cron tasks (cron-five-minutes … cron-monthly) had no overlap protection, unlike the queue worker. When the scheduler is triggered via more than one path — e.g. the built-in /api/cron web cron together with a system `schedule:run` cron, or a duplicate crontab entry — the same task can run concurrently. It also stacks when a task runs longer than its interval. In practice this causes intermittent failures around the nightly run (~01:00): two CronNightly handlers firing at once → race conditions, double processing, occasional DB deadlocks. Add `withoutOverlapping($ttl)` so a task already running is skipped instead of started a second time (mirrors the existing queue-worker entry). The TTL is a safety release so a crashed task cannot hold the lock indefinitely. No change to what the tasks do or when they run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
92 lines
2.3 KiB
PHP
92 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Events\CronFifteenMinute;
|
|
use App\Events\CronFiveMinute;
|
|
use App\Events\CronHourly;
|
|
use App\Events\CronMonthly;
|
|
use App\Events\CronNightly;
|
|
use App\Events\CronThirtyMinute;
|
|
use App\Events\CronWeekly;
|
|
use App\Services\CronService;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Schedule;
|
|
|
|
Log::setDefaultDriver('cron_daily');
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronFiveMinute());
|
|
})
|
|
->name('cron-five-minutes')
|
|
->everyFiveMinutes()
|
|
->withoutOverlapping(10);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronFifteenMinute());
|
|
})
|
|
->name('cron-fifteen-minutes')
|
|
->everyFifteenMinutes()
|
|
->withoutOverlapping(15);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronThirtyMinute());
|
|
})
|
|
->name('cron-thirty-minutes')
|
|
->everyThirtyMinutes()
|
|
->withoutOverlapping(30);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronHourly());
|
|
})
|
|
->name('cron-hourly')
|
|
->hourly()
|
|
->withoutOverlapping(55);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronNightly());
|
|
})
|
|
->name('cron-nightly')
|
|
->dailyAt('01:00')
|
|
->withoutOverlapping(120);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronWeekly());
|
|
})
|
|
->name('cron-weekly')
|
|
->weekly()
|
|
->withoutOverlapping(120);
|
|
|
|
Schedule::call(static function (): void {
|
|
event(new CronMonthly());
|
|
})
|
|
->name('cron-monthly')
|
|
->monthly()
|
|
->withoutOverlapping(120);
|
|
|
|
if (config('backup.backup.enabled', false)) {
|
|
Schedule::command('backup:run')->dailyAt('01:15');
|
|
Schedule::command('backup:clean')->dailyAt('01:30');
|
|
Schedule::command('backup:monitor')->dailyAt('01:45');
|
|
}
|
|
|
|
if (config('activitylog.enabled', false)) {
|
|
Schedule::command('activitylog:clean --force')->dailyAt('01:00');
|
|
}
|
|
|
|
Schedule::call(static function (): void {
|
|
// Update the last time the cron was run
|
|
app(CronService::class)->updateLastRunTime();
|
|
})
|
|
->name('update-last-run-time')
|
|
->everyMinute();
|
|
|
|
// Run queued jobs via cron for environments without Supervisor/systemd
|
|
if (config('phpvms.run_queued_jobs_in_cron', false)) {
|
|
Schedule::command('queue:work --stop-when-empty --tries=3 --sleep=3')
|
|
->name('queue-worker-cron')
|
|
->withoutOverlapping()
|
|
->runInBackground()
|
|
->everyMinute();
|
|
}
|