Passer au contenu principal

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éthodeDescription
->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éthodeDescription
->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

1

Ajouter l'entrée cron

Ajoutez à crontab -e :
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
2

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
Dernière modification le 13 juillet 2026