Pour faire tourner des queues Laravel en production sans perdre de tâches, cinq vérifications suffisent : un gardien qui relance les workers, un redémarrage à chaque mise en ligne, des délais cohérents entre eux, une alerte quand un job échoue, et des jobs qui supportent d'être rejoués. Un worker, c'est le processus qui exécute en arrière-plan les envois d'e-mails, de SMS ou de commandes.
Le cas : un worker lancé dans un terminal
L'équipe de Loop Origin décrit sur Medium une scène banale. En développement, on lance php artisan queue:work dans un terminal et tout part. On met en ligne, on ferme le terminal, et une semaine plus tard un client demande où est sa confirmation de commande.
Nous n'avons pu lire qu'une partie de leur article. Pour le reste, nous nous appuyons sur la documentation officielle de Laravel, qui va dans le même sens.
Un gardien, puis un redémarrage
Le worker charge votre code une fois et ne le relit plus.
S'il plante, ou si le serveur redémarre, personne ne le relance. Supervisor, un gestionnaire de processus courant sous Ubuntu, s'en charge.
À chaque déploiement, queue:restart demande aux workers de finir leur job en cours puis de s'arrêter, et Supervisor les relance avec le nouveau code. Ce signal transite par le cache : sans cache fonctionnel, il se perd.
L'extrait Medium conseille de reconstruire le cache de configuration avant ce redémarrage. Prudence sur un serveur : des variables d'environnement lues hors des fichiers de config peuvent revenir vides, et les intégrations tombent sans bruit.
Timeout et retry_after : les accorder
Deux délais se surveillent.
Le timeout est le temps maximal accordé à un job (60 secondes par défaut). retry_after est le moment où la file suppose qu'un job est mort et le confie à un autre worker (90 secondes par défaut dans la config Redis lue).
Le timeout doit rester plusieurs secondes sous retry_after, sinon le même job tourne deux fois. Un job volontairement long oblige donc à relever les deux ensemble. Les appels HTTP peuvent aussi ignorer le timeout du worker : il faut en fixer un côté client.
Tentatives, échecs, doublons
Par défaut, un job n'est tenté qu'une fois. Avec --tries=3 et un backoff progressif (le délai d'attente entre deux tentatives : 1, puis 5, puis 10 secondes, par exemple), un transporteur ou une passerelle SMS en panne n'est pas harcelé.
Quand les tentatives sont épuisées, le job atterrit dans la table failed_jobs. Sans alerte, personne ne le sait. La méthode failed() du job permet de prévenir quelqu'un, et queue:monitor signale une file qui gonfle.
Reste le doublon. La documentation ne le traite pas comme une règle, mais un blog indépendant conseille de partir du principe qu'un job peut s'exécuter deux fois. Il faut donc le rendre idempotent, c'est-à-dire sans effet double s'il est rejoué : avant de réserver un envoi, on vérifie que la commande n'a pas déjà un numéro de suivi.
Ce que nous en retenons pour une PME
Prenons une boutique qui envoie chaque commande au transporteur en arrière-plan. Les cinq vérifications se passent en quelques minutes par projet. Les échanges automatiques entre logiciels, comme ceux qui relient le back-office d'un de nos clients à son logisticien et à son transporteur, n'ont de valeur que si l'on voit quand une tâche reste coincée.
Pour une petite application, la base de données et un seul worker suffisent. Redis et Horizon ne se justifient qu'avec du volume ou un vrai besoin de visibilité. Côté coût, les composants sont open source ; nous n'avons trouvé aucun prix d'hébergement de référence.
Nous accompagnons des entreprises de Provence, notamment autour de Cornillon-Confoux, et notre offre d'hébergement et maintenance est là pour ce suivi.
- Supervisor relance les workers,
queue:restartfigure dans chaque déploiement. - Le timeout reste sous
retry_after, les deux relevés ensemble. - Des
trieset unbackoffsont définis sur les jobs qui appellent des services externes. - Une alerte surveille
failed_jobset la taille des files. - Les jobs de paiement, de stock et d'expédition sont idempotents.
Questions fréquentes
Supervisor est-il obligatoire pour les queues Laravel ?
Il faut au minimum un gestionnaire de processus qui relance les workers s'ils s'arrêtent. Supervisor est le choix courant sous Ubuntu et celui de la documentation Laravel.
Faut-il Redis pour les files d'attente Laravel ?
Non. Pour une petite application, le driver base de données suffit. Redis devient utile avec du volume, et Horizon, le tableau de bord de Laravel, l'exige.
Pourquoi un même job s'exécute-t-il deux fois ?
Souvent parce que le timeout dépasse retry_after, ou parce qu'un worker a planté avant de valider son travail. La parade est de rendre le job idempotent.
Que faire des jobs qui apparaissent dans failed_jobs ?
On les consulte avec queue:failed, on les relance avec queue:retry une fois la cause réglée, et on purge les anciens avec queue:prune-failed.