Queues,Task,job
Prérequis Généraux
Avant de commencer, assurez-vous d’avoir :
- Laravel installé : Créez un nouveau projet avec composer create-project laravel/laravel mon-projet.
- Base de données configurée : Par exemple, MySQL, SQLite ou PostgreSQL. Mettez à jour .env avec vos informations de connexion.
- Environnement local : PHP 8.1+, Composer, et un serveur local (par exemple, php artisan serve).
- Redis (optionnel) : Pour les middlewares avancés ou les performances des files d’attente.
- Accès à la ligne de commande : Pour exécuter les commandes Artisan.
Nous utiliserons la connexion database pour les files d’attente dans ce tutoriel, car elle est simple à configurer. Cependant, vous pouvez utiliser Redis ou d’autres pilotes en production.
1. Files d'Attente (Queues)
Les files d’attente permettent d’exécuter des tâches longues (comme l’envoi d’e-mails, le traitement d’images, ou l’importation de données) en arrière-plan, évitant ainsi de bloquer l’expérience utilisateur.
Configuration Initiale
-
Configurer la file d’attente : Modifiez votre fichier .env pour utiliser la connexion database :
envQUEUE_CONNECTION=database
-
Créer la table des jobs : Générez la migration pour stocker les jobs en file d’attente :
php artisan queue:table php artisan migrate
Cela crée une table jobs dans votre base de données.
-
Démarrer un worker : Pour traiter les jobs, vous devrez lancer un worker plus tard avec :
php artisan queue:work
1.1 Création d’un Job
Un Job est une classe PHP qui encapsule une tâche à exécuter dans la file d’attente. Imaginons que nous voulons créer un job pour envoyer une notification par e-mail à un utilisateur.
Étape 1 : Générer un Job
Utilisez la commande Artisan pour créer un job nommé SendWelcomeEmail :
php artisan make:job SendWelcomeEmail
Cela génère un fichier dans app/Jobs/SendWelcomeEmail.php.
Étape 2 : Implémenter le Job
Modifiez SendWelcomeEmail.php pour simuler l’envoi d’un e-mail :
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $userEmail; // Propriété pour stocker l'e-mail de l'utilisateur
/**
* Create a new job instance.
*/
public function __construct(string $userEmail)
{
$this->userEmail = $userEmail;
}
/**
* Execute the job.
*/
public function handle(): void
{
// Simuler l'envoi d'un e-mail (remplacez par Mail::to() en production)
Log::info("Sending welcome email to: {$this->userEmail}");
sleep(3); // Simuler une tâche longue de 3 secondes
Log::info("Welcome email sent to: {$this->userEmail}");
}
}
Explications :
- Constructeur : Le job accepte une adresse e-mail ($userEmail) comme paramètre pour personnaliser la tâche.
- Méthode handle : Contient la logique de la tâche. Ici, nous utilisons Log::info pour simuler l’envoi d’un e-mail et sleep(3) pour imiter une tâche longue.
- Traits Laravel :
- Dispatchable : Permet de dispatcher le job.
- InteractsWithQueue : Gère les interactions avec la file d’attente (par exemple, supprimer un job).
- Queueable : Définit sur quelle file d’attente le job sera exécuté.
- SerializesModels : Sérialise les modèles Eloquent pour une gestion correcte dans la file.
Étape 3 : Tester le Job
Pour tester manuellement, nous dispatcherons le job plus tard (voir Dispatching Jobs). Pour l’instant, notez que ce job est prêt à être utilisé.
1.2 Job Middleware
Les Job Middleware permettent d’ajouter des contrôles ou des transformations avant ou après l’exécution d’un job. Par exemple, nous pouvons limiter le nombre de jobs exécutés simultanément pour éviter de surcharger un serveur d’e-mails.
Étape 1 : Créer un Middleware
Générez un middleware nommé LimitEmailRate :
php artisan make:middleware LimitEmailRate
Cela crée un fichier dans app/Http/Middleware/LimitEmailRate.php.
Étape 2 : Implémenter le Middleware
Modifiez LimitEmailRate.php pour limiter l’envoi d’e-mails à 10 par minute :
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class LimitEmailRate
{
/**
* Handle an incoming job.
*/
public function handle($job, Closure $next)
{
$cacheKey = 'email_rate_limit';
$maxEmailsPerMinute = 10;
// Compter les e-mails envoyés dans la dernière minute
$emailCount = Cache::get($cacheKey, 0);
if ($emailCount >= $maxEmailsPerMinute) {
Log::warning("Email rate limit exceeded for job: {$job->userEmail}");
$job->release(60); // Relâcher le job pour réessayer après 60 secondes
return;
}
// Incrémenter le compteur
Cache::increment($cacheKey);
Cache::put($cacheKey, Cache::get($cacheKey), now()->addMinute());
// Exécuter le job
$next($job);
// Décrémenter après exécution réussie
Cache::decrement($cacheKey);
}
}
Explications :
- Cache : Nous utilisons le système de cache de Laravel (par défaut, fichier ou Redis si configuré) pour suivre le nombre d’e-mails envoyés.
- Logique :
- Si plus de 10 e-mails sont en cours dans la dernière minute, le job est relâché (release) pour réessayer après 60 secondes.
- Sinon, le compteur est incrémenté, le job est exécuté ($next($job)), puis le compteur est décrémenté.
- Cache Expiration : La clé expire après 1 minute pour réinitialiser le compteur.
Étape 3 : Appliquer le Middleware au Job
Modifiez app/Jobs/SendWelcomeEmail.php pour inclure le middleware :
<?php
namespace App\Jobs;
use App\Http\Middleware\LimitEmailRate;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $userEmail;
public function __construct(string $userEmail)
{
$this->userEmail = $userEmail;
}
/**
* Get the middleware the job should pass through.
*/
public function middleware()
{
return [new LimitEmailRate];
}
public function handle(): void
{
Log::info("Sending welcome email to: {$this->userEmail}");
sleep(3);
Log::info("Welcome email sent to: {$this->userEmail}");
}
}
Explications :
- Méthode middleware : Retourne un tableau de middlewares à appliquer au job.
- Instanciation : new LimitEmailRate applique notre middleware personnalisé.
1.3 Dispatching Jobs
Dispatcher un job signifie l’envoyer à la file d’attente pour qu’il soit traité par un worker.
Étape 1 : Créer une Route pour Dispatcher
Ajoutez une route dans routes/web.php pour tester le job :
use App\Jobs\SendWelcomeEmail;
Route::get('/send-welcome-email/{email}', function ($email) {
SendWelcomeEmail::dispatch($email);
return "Welcome email queued for: {$email}";
});
Explications :
- Route : La route accepte un paramètre {email} (par exemple, test@example.com).
- Dispatch : SendWelcomeEmail::dispatch($email) envoie le job à la file d’attente avec l’e-mail fourni.
- Retour : Un message confirme que le job est en file d’attente.
Étape 2 : Lancer le Worker
Pour traiter les jobs en file d’attente, exécutez :
php artisan queue:work
Étape 3 : Tester le Dispatch
-
Lancez le serveur Laravel :
php artisan serve
-
Accédez à l’URL : http://127.0.0.1:8000/send-welcome-email/test@example.com.
-
Vérifiez les logs dans storage/logs/laravel.log. Vous devriez voir :
text[2025-04-14 12:00:00] local.INFO: Sending welcome email to: test@example.com [2025-04-14 12:00:03] local.INFO: Welcome email sent to: test@example.com
Explications :
- Le worker récupère le job depuis la table jobs et exécute la méthode handle.
- Le middleware LimitEmailRate vérifie si la limite est atteinte avant d’exécuter le job.
- Si la limite est dépassée, le job est relâché, et vous verrez un message de warning dans les logs.
1.4 Job Batching
Le Job Batching permet de regrouper plusieurs jobs et d’exécuter une logique une fois que tous les jobs du lot sont terminés (ou si l’un échoue). Par exemple, nous pouvons envoyer des e-mails de bienvenue à plusieurs utilisateurs et enregistrer un log une fois terminé.
Étape 1 : Créer la Table des Batches
Générez la migration pour stocker les métadonnées des batches :
php artisan queue:batches-table
php artisan migrate
Cela crée une table job_batches dans votre base de données.
Étape 2 : Dispatcher un Batch
Ajoutez une route dans routes/web.php pour créer un lot de jobs :
use Illuminate\Support\Facades\Bus;
use App\Jobs\SendWelcomeEmail;
Route::get('/batch-welcome-emails', function () {
$batch = Bus::batch([
new SendWelcomeEmail('user1@example.com'),
new SendWelcomeEmail('user2@example.com'),
new SendWelcomeEmail('user3@example.com'),
])
->then(function () {
Log::info('All welcome emails sent successfully.');
})
->catch(function ($batch, $e) {
Log::error("Batch failed: {$e->getMessage()}");
})
->finally(function () {
Log::info('Batch processing completed.');
})
->name('welcome-emails-batch')
->dispatch();
return "Batch ID: {$batch->id}";
});
Explications :
- Batch : Bus::batch regroupe trois jobs SendWelcomeEmail pour différents e-mails.
- Callbacks :
- then : Exécuté si tous les jobs réussissent.
- catch : Exécuté si un job échoue (par exemple, une exception dans handle).
- finally : Exécuté dans tous les cas, après le succès ou l’échec.
- Nom : name donne un nom au batch pour faciliter son suivi.
- Retour : La route retourne l’ID du batch pour référence.
Étape 3 : Tester le Batch
-
Assurez-vous que le worker est en cours d’exécution :
php artisan queue:work
-
Accédez à : http://127.0.0.1:8000/batch-welcome-emails.
-
Vérifiez les logs. Vous devriez voir :
text[2025-04-14 12:01:00] local.INFO: Sending welcome email to: user1@example.com [2025-04-14 12:01:03] local.INFO: Welcome email sent to: user1@example.com [2025-04-14 12:01:03] local.INFO: Sending welcome email to: user2@example.com [2025-04-14 12:01:06] local.INFO: Welcome email sent to: user2@example.com [2025-04-14 12:01:06] local.INFO: Sending welcome email to: user3@example.com [2025-04-14 12:01:09] local.INFO: Welcome email sent to: user3@example.com [2025-04-14 12:01:09] local.INFO: All welcome emails sent successfully. [2025-04-14 12:01:09] local.INFO: Batch processing completed.
Explications :
- Chaque job est traité séquentiellement ou en parallèle (selon la configuration du worker).
- Une fois tous les jobs terminés, les callbacks then et finally s’exécutent.
- Si un job échoue (par exemple, en lançant une exception), catch et finally s’exécuteront.
Étape 4 : Simuler un Échec (Optionnel)
Pour tester le callback catch, modifiez temporairement SendWelcomeEmail.php pour lancer une exception sur un e-mail spécifique :
public function handle(): void
{
if ($this->userEmail === 'user2@example.com') {
throw new \Exception('Failed to send email to user2.');
}
Log::info("Sending welcome email to: {$this->userEmail}");
sleep(3);
Log::info("Welcome email sent to: {$this->userEmail}");
}
Relancez la route /batch-welcome-emails. Les logs montreront :
[2025-04-14 12:02:00] local.ERROR: Batch failed: Failed to send email to user2.
[2025-04-14 12:02:00] local.INFO: Batch processing completed.
- NotifyDeveloperTaskAssigned
- Description : Envoie une notification (par exemple, un e-mail) à un développeur lorsqu'une nouvelle tâche lui est assignée, avec les détails de la tâche et du projet.
- GenerateProjectReport
- Description : Génère un rapport (PDF ou texte) récapitulatif pour un projet, incluant ses tâches et les développeurs assignés, puis le sauvegarde.
- UpdateTaskStatus
- Description : Met à jour automatiquement l'état des tâches (par exemple, "en retard") en fonction de leur durée et de la date actuelle.
- SendProjectCompletionEmail
- Description : Envoie un e-mail aux développeurs et au chef de projet lorsque toutes les tâches d’un projet sont terminées.
- ExportDeveloperCVs
- Description : Exporte les CV des développeurs assignés à un projet spécifique dans un fichier ZIP pour un usage administratif.
- CalculateProjectCost
- Description : Calcule le coût total d’un projet en fonction des heures travaillées (duree) et du coût horaire (coutHeure) de chaque tâche.
- NotifyTaskDeadline
- Description : Envoie un rappel aux développeurs 24 heures avant l’échéance estimée d’une tâche, basée sur sa durée.
- ArchiveCompletedProjects
- Description : Archive les projets terminés (toutes les tâches sont marquées comme "terminées") dans une base de données ou un dossier séparé.
- ImportTasksFromCSV
- Description : Importe une liste de tâches à partir d’un fichier CSV pour un projet donné, en assignant les tâches aux développeurs.
- SyncTaskProgress
- Description : Met à jour l’état des tâches en synchronisant avec un système externe (par exemple, un outil de suivi comme Jira).
- GenerateDeveloperWorkloadReport
- Description : Crée un rapport sur la charge de travail d’un développeur, listant toutes ses tâches actives et leur durée totale.
- CleanTemporaryFiles
- Description : Supprime les fichiers temporaires (comme les photos de projets ou CVs) qui ne sont plus liés à des enregistrements actifs.
- SendWeeklyProjectSummary
- Description : Envoie un e-mail hebdomadaire à l’équipe avec un résumé de l’avancement des projets en cours.
- ValidateTaskAssignments
- Description : Vérifie que les tâches assignées ont des développeurs valides et que les projets existent, signalant les incohérences.
- BackupProjectData
- Description : Sauvegarde les données d’un projet (tâches, développeurs, métadonnées) dans un fichier JSON ou une base de données externe.
- AssignTasksAutomatically
- Description : Assigne automatiquement des tâches non attribuées à des développeurs disponibles en fonction de leur charge de travail.
- UpdateDeveloperProfiles
- Description : Met à jour les profils des développeurs (par exemple, photo ou CV) à partir d’un répertoire ou d’une source externe.
- NotifyProjectMilestone
- Description : Envoie une notification à l’équipe lorsqu’un jalon important du projet est atteint (par exemple, 50 % des tâches terminées).
2. Planification des Tâches (Task Scheduling)
La planification des tâches permet d’exécuter des commandes, des jobs, ou des closures à des intervalles réguliers, comme nettoyer une base de données ou envoyer des rapports.
Configuration Initiale
-
Configurer le Scheduler : En production, ajoutez une entrée Cron pour exécuter le scheduler chaque minute :
* * * * * cd /chemin/vers/votre-projet && php artisan schedule:run >> /dev/null 2>&1
En développement, vous pouvez tester manuellement ou utiliser schedule:work.
-
Vérifier les Logs : Les tâches planifiées peuvent écrire dans storage/logs/laravel.log pour le débogage.
2.1 Définition des Schedules
Les schedules sont définis dans app/Console/Kernel.php, dans la méthode schedule.
Étape 1 : Modifier le Kernel
Ouvrez app/Console/Kernel.php et ajoutez des tâches planifiées :
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\Log;
use App\Jobs\SendWelcomeEmail;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule): void
{
// Tâche 1 : Exécuter une closure toutes les 10 minutes
$schedule->call(function () {
Log::info('Running maintenance task every 10 minutes.');
// Exemple : Nettoyer les fichiers temporaires
})->everyTenMinutes()->name('maintenance-task');
// Tâche 2 : Dispatcher un job toutes les heures
$schedule->job(new SendWelcomeEmail('scheduled@example.com'))
->hourly()
->name('hourly-welcome-email');
// Tâche 3 : Exécuter une commande Artisan tous les jours à 23h59
$schedule->command('queue:retry all')
->dailyAt('23:59')
->name('retry-failed-jobs');
}
/**
* Register the commands for the application.
*/
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
Explications :
- Tâche 1 : Closure :
- call définit une closure exécutée toutes les 10 minutes (everyTenMinutes).
- Ici, nous écrivons un log, mais vous pourriez nettoyer des fichiers ou mettre à jour des statistiques.
- name donne un identifiant à la tâche pour la suivre.
- Tâche 2 : Job :
- job planifie notre job SendWelcomeEmail toutes les heures (hourly).
- L’e-mail scheduled@example.com est utilisé comme exemple.
- Tâche 3 : Commande Artisan :
- command exécute queue:retry all pour relancer les jobs échoués chaque jour à 23h59 (dailyAt).
- Fréquences : Laravel offre des méthodes comme everyMinute, everyFiveMinutes, daily, weekly, etc. Consultez la documentation pour toutes les options.
Pour ceux qui n'ont pas Kernel.php
Ouvrez ou créez le fichier routes/console.php.Voici un exemple
use Illuminate\Support\Facades\Schedule;
// Exemple : Exécuter une tâche toutes les minutes
Schedule::call(function () {
\Illuminate\Support\Facades\Log::info('Tâche planifiée exécutée !');
})->everyMinute();
....
.....
Schedule::call(function () {
// Votre logique ici
})->dailyAt('14:00');
Étape 2 : Lister les Tâches
Pour voir toutes les tâches planifiées :
php artisan schedule:list
Sortie attendue :
+--------------------+--------------------------+---------------------+
| Name | Command | Interval |
+--------------------+--------------------------+---------------------+
| maintenance-task | Closure | Every 10 minutes |
| hourly-welcome-email | App\Jobs\SendWelcomeEmail | Hourly |
| retry-failed-jobs | queue:retry all | Daily at 23:59 |
+--------------------+--------------------------+---------------------+
2.2 Exécution d’un Schedule
Étape 1 : Tester Manuellement
Pour exécuter le scheduler et vérifier les tâches dues :
php artisan schedule:run
Si l’heure correspond (par exemple, dans les 10 minutes pour maintenance-task), vous verrez des logs comme :
[2025-04-14 12:10:00] local.INFO: Running maintenance task every 10 minutes.
Pour le job horaire, assurez-vous que le worker est actif (php artisan queue:work), car les jobs planifiés sont envoyés à la file d’attente.
Étape 2 : Simuler en Développement
En développement, exécutez le scheduler en continu pour tester :
php artisan schedule:work
Cela exécute schedule:run chaque minute et affiche les tâches lancées. Exemple de sortie :
12:20:00 Running scheduled task: maintenance-task
Étape 3 : Vérifier les Résultats
-
Logs : Vérifiez storage/logs/laravel.log pour les messages de maintenance-task toutes les 10 minutes.
-
Jobs : Si le worker est actif, vous verrez les logs de SendWelcomeEmail toutes les heures :
text[2025-04-14 13:00:00] local.INFO: Sending welcome email to: scheduled@example.com [2025-04-14 13:00:03] local.INFO: Welcome email sent to: scheduled@example.com
-
Commande Artisan : La commande queue:retry all s’exécutera à 23h59. Vous pouvez tester manuellement avec :
php artisan queue:retry all
Étape 4 : Configurer Cron en Production
Assurez-vous que la tâche Cron est ajoutée sur votre serveur :
crontab -e
Ajoutez :
* * * * * cd /chemin/vers/votre-projet && php artisan schedule:run >> /dev/null 2>&1
Cela garantit que le scheduler est vérifié chaque minute.
Résumé des Commandes Utiles
Files d’Attente
- Créer un job : php artisan make:job NomDuJob
- Créer un middleware : php artisan make:middleware NomDuMiddleware
- Créer la table des jobs : php artisan queue:table
- Créer la table des batches : php artisan queue:batches-table
- Lancer le worker : php artisan queue:work
- Relancer les jobs échoués : php artisan queue:retry all
Planification des Tâches
- Tester le scheduler : php artisan schedule:run
- Simuler le scheduler : php artisan schedule:work
- Lister les tâches : php artisan schedule:list
Conseils Pratiques
- Débogage :
- Utilisez Log::info ou Log::error pour suivre l’exécution des jobs et des tâches.
- Vérifiez la table jobs ou job_batches pour diagnostiquer les problèmes.
- Production :
- Utilisez Supervisor pour garder les workers actifs.
- Configurez Redis ou un pilote comme sqs pour les files d’attente en production.
- Testez vos schedules avec schedule:list avant de déployer.
- Performances :
- Pour les batches volumineux, configurez plusieurs workers (php artisan queue:work --queue=high,low).
- Utilisez des fréquences adaptées pour les schedules (par exemple, évitez everyMinute pour les tâches lourdes).
- Documentation :
Exemple Complet en Action
Voici un scénario intégrant tous les éléments :
- Contexte : Une application envoie des e-mails de bienvenue aux nouveaux utilisateurs. Les e-mails sont limités à 10 par minute, certains sont envoyés en lot, et un e-mail planifié est envoyé toutes les heures à un administrateur.
- Code :
- Job : SendWelcomeEmail (section 1.1).
- Middleware : LimitEmailRate (section 1.2).
- Route de test : /send-welcome-email/{email} (section 1.3).
- Batch : /batch-welcome-emails (section 1.4).
- Schedule : Kernel.php avec une closure, un job, et une commande (section 2.1).
- Test :
- Lancez php artisan serve et php artisan queue:work.
- Accédez à /send-welcome-email/test@example.com : Vérifiez les logs.
- Accédez à /batch-welcome-emails : Vérifiez les logs pour les trois e-mails et les callbacks.
- Exécutez php artisan schedule:work : Vérifiez les logs toutes les 10 minutes et chaque heure.
Ce tutoriel fournit une base solide pour travailler avec les files d’attente et la planification des tâches dans Laravel. Si vous souhaitez approfondir un aspect (par exemple, gérer les échecs de jobs, utiliser Redis, ou créer des schedules complexes), n’hésitez pas à demander !