Quand un visiteur valide une commande ou envoie un formulaire, il s’attend à une réponse immédiate. Si cette action déclenche aussi l’envoi d’un e-mail de confirmation, la synchronisation avec un logiciel de gestion ou la génération d’une facture PDF, le faire attendre pendant que tout cela se termine dégrade son expérience, parfois jusqu’à l’erreur de délai dépassé. Les files d’attente règlent ce problème, et en apportent un autre bénéfice : la résistance aux pannes.
Le principe
Une file d’attente (queue) permet de dire à l’application : « fais cette tâche, mais pas maintenant : en arrière-plan, dans quelques secondes ». L’utilisateur reçoit une réponse immédiate, pendant qu’un processus séparé, le worker, traite la tâche réelle. Sur Laravel, ce sont les jobs ; sur Symfony, le composant Messenger.
Concrètement, avec Laravel
La tâche est une classe, envoyée dans la file au moment de la commande :
class EnvoyerConfirmationCommande implements ShouldQueue
{
use Queueable;
public int $tries = 5; // nombre d'essais avant l'échec
public array $backoff = [10, 60, 300]; // attente entre les essais, en secondes
public function __construct(public int $commandeId) {}
public function handle(): void
{
$commande = Commande::findOrFail($this->commandeId);
Mail::to($commande->email)->send(new ConfirmationCommande($commande));
}
}
// dans le contrôleur, après l'enregistrement de la commande
EnvoyerConfirmationCommande::dispatch($commande->id);
Avec Symfony, le principe est le même : un message ($bus->dispatch(new CommandeValidee($id))) et un gestionnaire qui le traite. Dans les deux cas, on transmet un identifiant plutôt que l’objet complet : la tâche relit les données à jour au moment où elle s’exécute.
Les tâches qui doivent presque toujours passer par une file
- L’envoi d’e-mails, de SMS et de notifications.
- Les appels à des API externes qui peuvent être lents ou temporairement indisponibles (transporteur, logiciel de gestion, service tiers).
- La génération de fichiers volumineux : factures, exports, rapports.
- Le traitement d’images ou de vidéos après un envoi.
- Le traitement des notifications reçues d’un service de paiement (webhooks).
- Toute tâche qui peut échouer et qu’il faut pouvoir réessayer automatiquement.
La résilience, et la règle qui va avec
Si un transporteur ou un service d’e-mails est temporairement indisponible, la tâche reste en attente et sera réessayée automatiquement, au lieu de faire échouer toute la commande pour le client. Le paiement lui-même reste immédiat ; c’est le traitement de sa confirmation qui gagne à passer par une file.
Une règle s’impose alors : une tâche réessayée ne doit jamais produire deux fois son effet (deux factures, deux e-mails, deux débits). On dit qu’elle doit être idempotente : avant d’agir, elle vérifie si le travail a déjà été fait, par exemple avec un statut « facture générée » enregistré en base.
Faire tourner le worker
Le worker est un processus qui tourne en permanence :
php artisan queue:work # Laravel
php bin/console messenger:consume async # Symfony
En production, il doit être relancé automatiquement s’il s’arrête (avec Supervisor ou systemd sur un serveur), et redémarré à chaque mise en ligne d’une nouvelle version du code. Sur un hébergement mutualisé qui n’autorise pas les processus permanents, une tâche planifiée qui lance le worker chaque minute jusqu’à ce que la file soit vide (queue:work --stop-when-empty) est un compromis acceptable pour les petits volumes.
Surveiller les échecs
Une file d’attente doit être supervisée. Les tâches qui ont épuisé leurs essais sont conservées à part et peuvent être examinées puis relancées (php artisan queue:failed et queue:retry sur Laravel, messenger:failed:show et messenger:failed:retry sur Symfony). Un tableau de bord comme Horizon, ou une simple alerte par e-mail quand des tâches échouent, évite qu’un service tiers en panne passe inaperçu pendant plusieurs jours.
La check-list
- E-mails, appels externes, fichiers lourds et webhooks passent par une file.
- Les tâches reçoivent des identifiants, pas des objets complets.
- Nombre d’essais et délais entre les essais définis.
- Tâches idempotentes : rejouées, elles ne produisent pas d’effet en double.
- Worker supervisé et redémarré à chaque mise en ligne.
- Échecs conservés, surveillés et relançables.
Pour aller plus loin : mon expertise : Développeur Laravel freelance · à lire aussi : Laravel ou Symfony : comment choisir pour votre prochain projet PHP
