Une Laravel queue vous permet de sortir les tâches lentes — envoyer un e-mail de bienvenue, traiter une image, appeler une API externe — du cycle requête-réponse pour les déplacer en arrière-plan. L'utilisateur n'attend plus que l'e-mail parte réellement ; la tâche est placée dans une file d'attente et traitée plus tard par un worker de fond, lorsque son tour arrive. Dans ce guide, nous allons mettre en place l'infrastructure de file d'attente de zéro, écrire notre propre classe de job, lancer le worker et gérer les échecs de manière robuste.
Pourquoi avez-vous besoin d'une file d'attente ?
Dans une application synchrone, tout se passe à l'intérieur de la même requête. L'utilisateur soumet le formulaire d'inscription, vous envoyez l'e-mail, vous redimensionnez peut-être une image, et ce n'est qu'ensuite que la réponse revient au navigateur. Si le serveur de mail est lent, l'utilisateur attend plusieurs secondes. Une file d'attente sépare ces tâches :
- Rapidité : le travail lent part en arrière-plan et la réponse revient instantanément.
- Résilience : si un job échoue, il peut être réessayé automatiquement.
- Scalabilité : vous pouvez lancer plusieurs workers et répartir la charge.
Choisir un driver de file d'attente
Laravel prend en charge plusieurs drivers de file d'attente, tous derrière une seule et même API. Vous en choisissez un avec la variable QUEUE_CONNECTION de votre fichier .env :
QUEUE_CONNECTION=database
Les options courantes sont :
sync— la valeur par défaut ; le job s'exécute immédiatement dans la même requête. Inutile en dehors du développement local.database— stocke les jobs dans une table de base de données. Facile à mettre en place, largement suffisant pour les petits/moyens projets.redis— le choix rapide et recommandé pour les gros volumes.sqs— une file d'attente gérée et serverless via Amazon SQS.
Si vous utilisez le driver database, il vous faut une table pour la file. Laravel fournit une commande pour la générer :
php artisan make:queue-table
php artisan migrate
Créer votre première classe de job
Un job est une unité de travail unique à exécuter dans la file. Créez-en un avec artisan :
php artisan make:job SendWelcomeEmail
Cela génère app/Jobs/SendWelcomeEmail.php. Une classe qui implémente l'interface ShouldQueue est automatiquement mise en file. La méthode handle() contient la logique réelle du travail :
<?php
namespace App\Jobs;
use App\Models\User;
use App\Mail\WelcomeMail;
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\Mail;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(public User $user) {}
public function handle(): void
{
Mail::to($this->user)->send(new WelcomeMail($this->user));
}
}
Un point à noter : nous passons un modèle User au constructeur. Grâce au trait SerializesModels, seule la clé primaire est sérialisée plutôt que le modèle entier ; lorsque le job s'exécute, le modèle est rechargé à neuf depuis la base de données.
Distribuer le job dans la file (dispatch)
Pour déclencher le job, vous utilisez dispatch. La forme la plus simple est la méthode statique :
use App\Jobs\SendWelcomeEmail;
SendWelcomeEmail::dispatch($user);
Avec des méthodes chaînées fluides, vous pouvez régler la façon dont le job s'exécute :
SendWelcomeEmail::dispatch($user)
->onQueue('emails') // vers une file précise
->delay(now()->addMinutes(5)); // avec 5 minutes de délai
Pour exécuter plusieurs jobs en séquence, utilisez Bus::chain(), et pour des groupes parallèles, Bus::batch(). Il est tout à fait acceptable de commencer petit ; vous ajoutez ces fonctionnalités au fur et à mesure des besoins.
Lancer le worker
Les jobs arrivent dans la file, mais il faut un processus pour les traiter. C'est à cela que sert le worker :
php artisan queue:work
Cette commande tourne en continu et attend de nouveaux jobs. Quelques drapeaux importants :
--queue=emails,default— écoute les files par ordre de priorité.--tries=3— combien de fois un job est tenté en cas d'échec.--timeout=60— combien de secondes un seul job peut durer au maximum.
Un point crucial : queue:work charge votre application en mémoire. Quand vous modifiez le code, le worker continue d'exécuter l'ancienne version. C'est pourquoi vous devez redémarrer le worker après chaque déploiement :
php artisan queue:restart
En production, utilisez un gestionnaire de processus comme Supervisor pour que le worker redémarre même s'il plante. Supervisor surveille le processus queue:work et le relance automatiquement si nécessaire.
Gérer les jobs en échec
Les jobs échouent parfois : le serveur de mail ne répond pas, une API dépasse son délai. Quand toutes les tentatives sont épuisées, Laravel enregistre le job dans la table failed_jobs. Créez la migration correspondante :
php artisan make:queue-failed-table
php artisan migrate
Vous pouvez lister les jobs en échec et les réessayer :
php artisan queue:failed # lister
php artisan queue:retry all # tout réessayer
php artisan queue:flush # tout supprimer
Si vous ajoutez une méthode failed() à votre classe de job, elle s'exécute lorsque le job échoue définitivement ; vous pouvez y notifier un administrateur ou écrire un log. Vous pouvez aussi utiliser la propriété $backoff pour ajouter une attente entre les tentatives — essentiel pour ne pas saturer un service instable lors de pannes temporaires.
Questions fréquentes
Comment choisir entre les drivers database et redis ?
Jusqu'à quelques milliers de jobs par jour, database convient parfaitement et ne demande aucune infrastructure supplémentaire. Passez à Redis si vous avez besoin d'un gros volume, d'une faible latence ou de fonctionnalités avancées comme Bus::batch(). La plupart des projets commencent avec database et migrent quand le besoin se présente.
Pourquoi dois-je redémarrer le worker après un changement de code ?
Parce que queue:work est un processus à longue durée de vie qui charge l'application une seule fois en mémoire. Le code modifié ne se reflète pas dans la copie en mémoire. php artisan queue:restart laisse les jobs en cours se terminer et indique au worker de redémarrer en toute sécurité.
Combien de temps un job peut-il s'exécuter ?
Cela se règle avec le drapeau --timeout (60 secondes par défaut). Pour des jobs plus longs, augmentez la valeur, mais veillez à ce que le timeout soit inférieur au réglage retry_after de la file ; sinon le même job pourrait être traité deux fois.
Si vous voulez voir votre file d'attente en action, nous pouvons repérer ensemble les points lents de votre projet et les déplacer en arrière-plan ; contactez-moi pour mettre en place ou optimiser votre infrastructure Laravel.