Laravel cookbook · Beginner

Schedule tasks safely on multiple servers

Cron jobs run on every server, overlap with themselves, and fail silently.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Define schedules in routes/console.php, prevent overlap, run once across servers with onOneServer() (needs a shared cache), and report failures. Run schedule:run every minute from one cron entry.

Solution

<?php
// routes/console.php
use App\Jobs\SendWeeklyDigest;
use Illuminate\Support\Facades\Schedule;

Schedule::command('orders:expire-unpaid')
    ->everyFiveMinutes()
    ->withoutOverlapping(10)
    ->onOneServer()
    ->onFailure(fn () => logger()->error('orders:expire-unpaid failed'));

Schedule::job(new SendWeeklyDigest, 'mail')
    ->weeklyOn(1, '08:00')
    ->timezone('Europe/Berlin')
    ->onOneServer();

Schedule::command('model:prune')->daily()->onOneServer();
Schedule::command('sanctum:prune-expired --hours=24')->daily()->onOneServer();
# crontab on each server (or a single scheduler container)
# * * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1

php artisan schedule:list      # verify what will run and when
php artisan schedule:work      # run the scheduler in the foreground (containers, local)

Pitfalls

  • onOneServer() with a cache store that isn't shared (file, array).
  • Long tasks in the scheduler process; dispatch jobs to the queue instead.
  • Timezone surprises: schedules use the app timezone unless set per task.

Variations

  • Add ->pingOnSuccess($url) to report to a heartbeat monitor (Healthchecks, Oh Dear).
  • Use ->runInBackground() for commands that shouldn't delay other scheduled tasks.

Further reading: Task scheduling

Reference: https://laravel.com/docs/13.x/scheduling

More Laravel recipes

Was this page helpful?