Dépannage · Laravel
Le scheduler Laravel ne tourne pas, ou vous cherchez une alternative ?
Pourquoi le scheduler de Laravel s’arrête en silence — l’entrée cron manquante, le mauvais utilisateur, l’environnement et les tâches qui se chevauchent — et comment y remédier, ou le remplacer.
Le scheduler de Laravel est piloté par une seule entrée cron système. Si elle est incorrecte — ou l’environnement sous-jacent — toutes les tâches planifiées s’arrêtent en silence. Voici la checklist.
1. L’unique entrée cron doit exister
Laravel a besoin d’exactement une ligne de crontab appelant schedule:run chaque
minute. Vérifiez qu’elle existe pour le bon utilisateur (généralement votre
utilisateur de déploiement, pas root) :
crontab -l
Elle doit être :
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
Si elle manque, ajoutez-la avec crontab -e. Une erreur de déploiement courante est
de l’ajouter en tant que root alors que l’app tourne en tant que www-data (ou
inversement).
2. Utilisez le bon binaire PHP et un chemin absolu
Sous cron, php peut ne pas se résoudre, ou être la mauvaise version. Utilisez le
chemin complet et celui du projet :
* * * * * cd /var/www/app && /usr/bin/php8.3 artisan schedule:run >> /dev/null 2>&1
3. L’environnement diffère de votre shell
Cron ne charge pas votre profil shell, donc tout ce que vous y définissez manque.
Laravel lit .env, ce qui est bien — mais si vos tâches appellent d’autres
binaires, donnez-leur un PATH explicite. Assurez-vous aussi que APP_ENV et la
configuration des files/cache correspondent à la production.
4. Vous avez masqué la sortie et ne pouvez plus déboguer
>> /dev/null 2>&1 cache tout, y compris les erreurs. Journalisez-la
temporairement :
* * * * * cd /var/www/app && php artisan schedule:run >> storage/logs/schedule.log 2>&1
Puis exécutez php artisan schedule:run à la main et lisez la sortie — la plupart
des échecs (permissions, env manquant, connexion BD) apparaissent immédiatement.
5. Les tâches se chevauchent ou se bloquent
Une tâche longue qui tourne chaque minute peut s’accumuler. Utilisez les garde-fous de Laravel pour qu’une exécution lente ne bloque pas la suivante :
$schedule->command('reports:build')
->hourly()
->withoutOverlapping()
->onOneServer();
Le problème de fond : le scheduler peut s’arrêter et rester silencieux
Si schedule:run cesse de se déclencher — le serveur a redémarré, la crontab a été
effacée au déploiement, PHP a été mis à jour — Laravel n’a aucun moyen de vous le
dire. Vos rapports et e-mails en file s’arrêtent tout simplement.
Envoyez un ping heartbeat depuis une tâche planifiée pour savoir que le scheduler lui-même est vivant :
$schedule->call(function () {
Http::timeout(10)->get('https://ping.steadycron.com/<votre-jeton-ping>');
})->everyFifteenMinutes();
Si ce ping manque, SteadyCron vous alerte — le scheduler est en panne, avant que vos utilisateurs ne s’en aperçoivent.
Vous cherchez une alternative au scheduler Laravel, tout simplement ?
Si vous en avez assez de corriger sans cesse le même type de problème — une
crontab effacée, une migration de serveur qui fait disparaître la seule ligne
dont tout dépend, un schedule:run qui se déclenche techniquement mais échoue
en silence — vous n’êtes pas obligé de garder ce point de défaillance unique.
La plupart des entrées $schedule->command(...) et $schedule->call(...)
peuvent devenir une route :
// routes/api.php
Route::post('/cron/build-reports', function () {
Artisan::call('reports:build');
return response()->json(['ok' => true]);
})->middleware('auth.cron-token');
SteadyCron appelle ensuite ce point de terminaison selon le planning — avec
son propre réessai/backoff, son délai d’expiration et son journal
d’exécution — au lieu de dépendre de l’existence d’une entrée cron système, du
bon binaire PHP, ou du déclenchement effectif de schedule:run. Le planning
vit désormais dans SteadyCron, survit intact aux migrations de serveur, et
chaque exécution affiche son code de statut et sa réponse, pas seulement ce
qui a atterri dans storage/logs.
C’est la même idée que celle développée sur la page alternative au cron Docker — sortir le déclencheur du processus censé simplement répondre aux requêtes.