Fehlerbehebung · Laravel

Laravel-Scheduler läuft nicht? Den stillen Ausfall beheben

Warum Laravels Scheduler still ausfällt — der fehlende Cron-Eintrag, falscher Benutzer, Umgebung und überlappende Tasks — und wie Sie es beheben.

Laravels Scheduler wird von einem einzigen System-Cron-Eintrag angetrieben. Ist der falsch — oder die Umgebung darunter — fallen alle geplanten Tasks still aus. Hier die Checkliste.

1. Der eine Cron-Eintrag muss existieren

Laravel braucht genau eine Crontab-Zeile, die schedule:run jede Minute aufruft. Stellen Sie sicher, dass sie für den richtigen Benutzer existiert (meist Ihr Deploy-Benutzer, nicht root):

crontab -l

Sie sollte lauten:

* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1

Fehlt sie, fügen Sie sie mit crontab -e hinzu. Ein häufiger Deploy-Fehler ist, sie als root hinzuzufügen, während die App als www-data läuft (oder umgekehrt).

2. Nutzen Sie das richtige PHP-Binary und absolute Pfade

Unter Cron lässt sich php womöglich nicht auflösen oder ist die falsche Version. Nutzen Sie den vollen Pfad und den Projektpfad:

* * * * * cd /var/www/app && /usr/bin/php8.3 artisan schedule:run >> /dev/null 2>&1

3. Die Umgebung unterscheidet sich von Ihrer Shell

Cron lädt Ihr Shell-Profil nicht, also fehlt alles, was Sie dort setzen. Laravel liest .env, was in Ordnung ist — aber wenn Ihre Tasks andere Binaries aufrufen, geben Sie ihnen einen expliziten PATH. Stellen Sie außerdem sicher, dass APP_ENV sowie Queue-/Cache-Konfiguration zur Produktion passen.

4. Sie haben die Ausgabe unterdrückt und können nun nicht debuggen

>> /dev/null 2>&1 verbirgt alles, auch Fehler. Loggen Sie es vorübergehend:

* * * * * cd /var/www/app && php artisan schedule:run >> storage/logs/schedule.log 2>&1

Führen Sie dann php artisan schedule:run von Hand aus und lesen Sie die Ausgabe — die meisten Fehler (Berechtigungen, fehlende Env, DB-Verbindung) zeigen sich sofort.

5. Tasks überlappen oder hängen

Ein langer Task, der jede Minute läuft, kann sich stauen. Nutzen Sie Laravels Guards, damit ein langsamer Lauf den nächsten nicht blockiert:

$schedule->command('reports:build')
    ->hourly()
    ->withoutOverlapping()
    ->onOneServer();

Das tiefere Problem: Der Scheduler kann stoppen und still bleiben

Stoppt schedule:run — der Server wurde neu gestartet, die Crontab beim Deploy gelöscht, PHP aktualisiert — hat Laravel keine Möglichkeit, es Ihnen zu sagen. Ihre in Queues eingereihten Reports und E-Mails hören einfach auf.

Pingen Sie einen Heartbeat aus einem geplanten Task, damit Sie wissen, dass der Scheduler selbst lebt:

$schedule->call(function () {
    Http::timeout(10)->get('https://ping.steadycron.com/<ihr-ping-token>');
})->everyFifteenMinutes();

Bleibt dieser Ping aus, alarmiert Sie SteadyCron — der Scheduler ist down, bevor Ihre Nutzer es merken.