Qu’est-ce que la planification
Traditionnellement, il fallait écrire manuellement une entrée cron par tâche périodique.
Cette approche externalise les définitions du code : aucune versioning, et un SSH est nécessaire pour modifier.
Avec le planificateur Laravel, vous définissez les planifications directement dans l’application de manière fluide.
Une seule entrée cron sur le serveur, et les définitions vivent avec votre code, sous contrôle de version.
Convention : définir les planifications dans routes/console.php.
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;
Schedule::call(function () {
DB::table('recent_users')->delete();
})->daily();
schedule:list liste les tâches et affiche leur prochaine exécution.php artisan schedule:list
Flux d’exécution
Définir des planifications
Écrivez dans routes/console.php. Vous pouvez aussi passer par withSchedule dans bootstrap/app.php.
// bootstrap/app.php
use Illuminate\Console\Scheduling\Schedule;
->withSchedule(function (Schedule $schedule) {
$schedule->call(new DeleteRecentUsers)->daily();
})
Types de tâches planifiables
Commandes Artisan
Utilisez command. Nom de commande ou classe.
use App\Console\Commands\SendEmailsCommand;
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send Taylor --force')->daily();
Schedule::command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();
Commandes définies par closure : chaînez directement.
Artisan::command('delete:recent-users', function () {
DB::table('recent_users')->delete();
})->purpose('Delete recent users')->daily();
Jobs de queue
job planifie un job de queue, sans closure explicite.
use App\Jobs\Heartbeat;
use Illuminate\Support\Facades\Schedule;
Schedule::job(new Heartbeat)->everyFiveMinutes();
Nom de queue et connexion :
Schedule::job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();
Commandes shell
exec exécute une commande OS.
use Illuminate\Support\Facades\Schedule;
Schedule::exec('node /home/forge/script.js')->daily();
Closures
call planifie une closure.
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;
Schedule::call(function () {
DB::table('recent_users')->delete();
})->daily();
Objet avec __invoke :
Schedule::call(new DeleteRecentUsers)->daily();
Fréquences
Méthodes principales
| Méthode | Description |
|---|
->everySecond() | Toutes les secondes |
->everyMinute() | Chaque minute |
->everyFiveMinutes() | Toutes les 5 min |
->everyFifteenMinutes() | Toutes les 15 min |
->everyThirtyMinutes() | Toutes les 30 min |
->hourly() | Chaque heure |
->hourlyAt(17) | Chaque heure à HH:17 |
->daily() | À 0 h |
->dailyAt('13:00') | À 13 h |
->twiceDaily(1, 13) | 1 h et 13 h |
->weekly() | Dimanche à 0 h |
->weeklyOn(1, '8:00') | Lundi à 8 h |
->monthly() | 1er du mois à 0 h |
->monthlyOn(4, '15:00') | Le 4 à 15 h |
->quarterly() | 1er du trimestre à 0 h |
->yearly() | 1er janvier à 0 h |
->timezone('Europe/Paris') | Spécifier le fuseau |
Expression cron directe
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')->cron('0 9 * * *'); // 9 h chaque jour
Combinaisons
use Illuminate\Support\Facades\Schedule;
// Lundi à 13 h
Schedule::call(function () {
// ...
})->weekly()->mondays()->at('13:00');
// Jours ouvrés, 8 h → 17 h, chaque heure
Schedule::command('foo')
->weekdays()
->hourly()
->timezone('Europe/Paris')
->between('8:00', '17:00');
Fuseau horaire
timezone sur une tâche :
use Illuminate\Support\Facades\Schedule;
Schedule::command('report:generate')
->timezone('Europe/Paris')
->at('9:00');
Ou par défaut pour tout via config/app.php.
// config/app.php
'schedule_timezone' => 'Europe/Paris',
Les fuseaux avec heure d’été peuvent exécuter une tâche deux fois ou pas du tout au moment du changement. Préférez UTC dans la mesure du possible.
Contraintes
when / skip
Exécute si when retourne true, ignore si skip retourne true.
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')->daily()->when(function () {
return true;
});
Schedule::command('emails:send')->daily()->skip(function () {
return true;
});
environments
Schedule::command('emails:send')
->daily()
->environments(['staging', 'production']);
Contraintes horaires
Schedule::command('emails:send')
->hourly()
->between('7:00', '22:00');
Schedule::command('emails:send')
->hourly()
->unlessBetween('23:00', '4:00');
Jours
| Méthode | Description |
|---|
->weekdays() | Jours ouvrés |
->weekends() | Week-end |
->mondays() à ->sundays() | Un jour précis |
->days([0, 3]) | Dimanche (0) et mercredi (3) |
use Illuminate\Support\Facades;
use Illuminate\Console\Scheduling\Schedule;
Facades\Schedule::command('emails:send')
->hourly()
->days([Schedule::SUNDAY, Schedule::WEDNESDAY]);
Éviter la superposition
Par défaut, une tâche peut commencer même si la précédente tourne encore. withoutOverlapping attend la fin.
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')->withoutOverlapping();
TTL du verrou (minutes) ; 24 h par défaut.
Schedule::command('emails:send')->withoutOverlapping(10);
Le verrou passe par le cache. Si la tâche reste bloquée, libérez-le avec schedule:clear-cache.php artisan schedule:clear-cache
Multi-serveurs
Avec onOneServer, une seule instance de serveur exécute la tâche parmi toutes.
use Illuminate\Support\Facades\Schedule;
Schedule::command('report:generate')
->fridays()
->at('17:00')
->onOneServer();
Nécessite un driver de cache database, memcached, dynamodb ou redis, partagé entre tous les serveurs.
Flux distribué avec onOneServer()
Grouper des tâches
Appliquez des réglages communs avec group.
use Illuminate\Support\Facades\Schedule;
Schedule::daily()
->onOneServer()
->timezone('Europe/Paris')
->group(function () {
Schedule::command('emails:send --force');
Schedule::command('emails:prune');
});
Exécution en arrière-plan
Les tâches simultanées s’exécutent par défaut dans l’ordre de définition. runInBackground lance en parallèle.
use Illuminate\Support\Facades\Schedule;
Schedule::command('analytics:report')
->daily()
->runInBackground();
Disponible uniquement avec command et exec.
Mode maintenance
En mode maintenance, les tâches planifiées ne s’exécutent pas. evenInMaintenanceMode force l’exécution.
Schedule::command('emails:send')->evenInMaintenanceMode();
Flux
Pause du planificateur
Suspendez sans modifier le code.
# Pause
php artisan schedule:pause
# Reprise
php artisan schedule:continue
Pour continuer certaines tâches malgré la pause : evenWhenPaused. Utile pour la supervision.
Schedule::command('emails:send')->evenWhenPaused();
Gestion des sorties
Fichiers
sendOutputTo écrit dans un fichier.
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')
->daily()
->sendOutputTo(storage_path('logs/emails-send.log'));
appendOutputTo ajoute au fichier existant.
Schedule::command('emails:send')
->daily()
->appendOutputTo(storage_path('logs/emails-send.log'));
Par e-mail
emailOutputTo envoie la sortie par e-mail. Nécessite la configuration mail.
Schedule::command('report:generate')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('[email protected]');
Uniquement en cas d’échec : emailOutputOnFailure.
Schedule::command('report:generate')
->daily()
->emailOutputOnFailure('[email protected]');
Hooks
before / after avant et après l’exécution.
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')
->daily()
->before(function () {
// Avant
})
->after(function () {
// Après
});
Succès / échec via onSuccess / onFailure.
use Illuminate\Support\Stringable;
Schedule::command('emails:send')
->daily()
->onSuccess(function (Stringable $output) {
// OK
})
->onFailure(function (Stringable $output) {
// KO
});
Déploiement sur serveur
Ajouter l'entrée cron
Ajoutez à crontab -e :* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
Vérifier
Liste des tâches et prochaines exécutions :php artisan schedule:list
Avec Laravel Cloud, la planification est gérée sans configuration cron.
En local
schedule:work maintient un planificateur en foreground.
php artisan schedule:work
Il tourne jusqu’à Ctrl+C.
Sous-minute
Cron ne descend pas sous la minute. Laravel offre everySecond().
use Illuminate\Support\Facades\Schedule;
Schedule::call(function () {
DB::table('recent_users')->delete();
})->everySecond();
Lorsque des tâches sous-minute existent, schedule:run tourne jusqu’à la fin de la minute.
Déléguez le travail à des jobs / commandes en arrière-plan : sinon, une tâche longue bloque les suivantes.
Pour interrompre un schedule:run pendant un déploiement :
php artisan schedule:interrupt
Commandes utiles
# Lister
php artisan schedule:list
# Exécuter (appelé par cron)
php artisan schedule:run
# Local, en boucle
php artisan schedule:work
# Pause
php artisan schedule:pause
# Reprise
php artisan schedule:continue
# Libérer les verrous
php artisan schedule:clear-cache
# Interrompre les sous-minutes
php artisan schedule:interrupt