Laravel 12 : Deferred Queue et Failover, les deux fonctionnalités qui changent tout
Laravel 12.35 débarque avec deux fonctionnalités que tout le monde attendait pour les files d'attente : la connexion deferred et le système failover. Fini les expériences utilisateur cassées par des traitements lourds, fini les jobs perdus lors d'une panne Redis. Tout est maintenant intégré, simple, et ça fonctionne out of the box.
Voyons comment optimiser vos queues en quelques lignes de configuration.
Vous êtes un "visual learner" ? Regardez mon tutorial vidéo sur YouTube:
Le problème des queues synchrones
Avant Laravel 12.35, gérer correctement les files d'attente était un compromis difficile. Avec une connexion sync, vos jobs s'exécutent immédiatement, bloquant la réponse HTTP :
1// Dans config/queue.php2'default' => env('QUEUE_CONNECTION', 'sync'),
Le flux d'exécution est prévisible mais problématique :
- L'utilisateur soumet le formulaire
- Le podcast est créé en base
- Le job lourd s'exécute (traitement, encodage, etc.)
- L'utilisateur attend...
- Enfin, la redirection avec le message de succès
Résultat : une expérience utilisateur cassée. L'utilisateur ne comprend pas pourquoi ça prend du temps, pense que ça ne fonctionne pas, et clique plusieurs fois.
Passer à Redis ou Database résout le problème de performance, mais en crée un autre : que se passe-t-il si Redis tombe en production ? Vos jobs sont perdus. Définitivement.
La solution Laravel : deferred et failover
Avec Laravel 12.35, deux nouvelles connexions résolvent ces problèmes élégamment.
La connexion deferred : l'expérience utilisateur avant tout
La connexion deferred est un game-changer. Elle fonctionne comme le helper defer() mais pour vos queues.
Ca ne vous dit rien ? N'hésitez pas à lire notre article à propos de defer().
Dans votre .env, ajoutez simplement :
1QUEUE_CONNECTION=deferred
ou si vous ciblez un job en particulier comme dans notre exemple :
1PodcastJob::dispatch($podcast)->onConnection('deferred');
C'est tout. Vraiment. Voici ce qui se passe maintenant :
- L'utilisateur soumet le formulaire
- Le podcast est créé en base
- La redirection s'effectue immédiatement
- Une fois la réponse HTTP envoyée avec succès (code 2xx), le job s'exécute
1use Illuminate\Support\Facades\Bus; 2use App\Jobs\ProcessPodcast; 3 4public function store(Request $request) 5{ 6 $podcast = Podcast::create($request->validated()); 7 8 // Avec la connexion deferred, ce job s'exécute 9 // APRÈS la redirection10 PodcastJob::dispatch($podcast)->onConnection('deferred');11 12 return redirect()->route('podcasts.index')13 ->with('success', 'Podcast créé !');14}
Le job utilise toujours le même driver (sync dans cet exemple), mais il est différé jusqu'à la fin de la requête. L'utilisateur voit immédiatement son message de succès, et le traitement lourd se fait en arrière-plan.
Important : le job ne s'exécute que si la réponse HTTP est réussie. En cas d'erreur 4xx ou 5xx, le job n'est jamais dispatché. C'est un comportement de sécurité intégré.
Le système failover : ne perdez plus jamais un job
Le failover est encore plus crucial pour la production. C'est votre filet de sécurité.
Configuration du failover
Dans votre .env :
1QUEUE_CONNECTION=failover
Puis dans config/queue.php, définissez votre liste prioritaire de drivers :
1'connections' => [ 2 'failover' => [ 3 'driver' => 'failover', 4 'connections' => [ 5 'redis', // Essaie Redis en premier 6 'database', // Se rabat sur Database si Redis échoue 7 ], 8 ], 9 10 'redis' => [11 'driver' => 'redis',12 'connection' => 'default',13 'queue' => env('REDIS_QUEUE', 'default'),14 'retry_after' => 90,15 'block_for' => null,16 ],17 18 'database' => [19 'driver' => 'database',20 'table' => 'jobs',21 'queue' => 'default',22 'retry_after' => 90,23 ],24],
Comment ça fonctionne en production ?
Imaginez le scénario catastrophe : vous êtes en production, Redis crashe.
Sans failover :
- Vos utilisateurs soumettent des formulaires
- Les jobs tentent de se connecter à Redis
- Échec de connexion → Exception
- Les jobs sont perdus définitivement
- Aucun worker ne les traitera jamais
Avec failover :
- Vos utilisateurs soumettent des formulaires
- Les jobs tentent Redis → échec
- Basculement automatique sur Database
- Les jobs sont sauvegardés en base de données
- Vos workers peuvent continuer à les traiter depuis la base
1# Redis est down2$ sudo systemctl stop redis3 4# Les logs vous préviennent5[WARNING] Redis connection failed, falling back to database6 7# Les jobs continuent de fonctionner !8$ php artisan queue:work database
Une fois Redis de retour en ligne, vos nouveaux jobs l'utiliseront automatiquement. Les anciens jobs en base peuvent être traités par un worker dédié :
1# Worker pour les jobs failover stockés en database2$ php artisan queue:work database --queue=default
Combiner deferred et failover
La vraie puissance apparaît quand vous combinez les deux approches :
1QUEUE_CONNECTION=deferred_failover
1'connections' => [2 'deferred_failover' => [3 'driver' => 'failover',4 'connections' => [5 'redis',6 'database',7 ],8 ],9],
Vous obtenez le meilleur des deux mondes :
- Expérience utilisateur optimale : réponse HTTP immédiate
- Haute disponibilité : basculement automatique en cas de panne
- Aucune perte de données : tous les jobs sont sauvegardés quelque part
Migration depuis le driver Database
Si vous utilisiez déjà le driver database pour vos queues, assurez-vous d'avoir la table nécessaire :
1# Publier la migration2$ php artisan queue:table3 4# Exécuter la migration5$ php artisan migrate
La table jobs contiendra vos jobs en attente :
1| id | queue | payload | attempts | reserved_at | available_at | created_at |2|----|-------|---------|----------|-------------|--------------|------------|3| 1 | default | {...} | 0 | NULL | 2025-11-02 | 2025-11-02 |
Pour vérifier que vos jobs sont bien enregistrés :
1$ php artisan tinker2>>> App\Models\Job::count()3=> 3
Configuration du failover pour le cache
Le système failover ne fonctionne pas que pour les queues. Il est également disponible pour le cache :
1// Dans config/cache.php 2'default' => env('CACHE_DRIVER', 'failover'), 3 4'stores' => [ 5 // vos autres configurations de drivers... 6 7 'failover' => [ 8 'driver' => 'failover', 9 'stores' => [10 'redis',11 'file',12 ],13 ],14],
Même logique : si Redis tombe, le cache bascule automatiquement sur les fichiers. Votre application continue de fonctionner.
Conclusion
Les connexions deferred et failover de Laravel 12.35 sont exactement ce qu'on attendait : simples, puissantes, et invisibles.
Plus besoin de choisir entre performance et fiabilité. Plus besoin de gérer manuellement les basculements entre services. Tout est géré nativement, de la réponse HTTP optimale à la haute disponibilité en production.
C'est une de ces features qui paraît simple en surface mais qui cache une complexité énorme. Et c'est justement ça qui est génial : toute cette complexité est abstraite. Vous vous concentrez sur votre logique métier, Laravel gère le reste.
Deux lignes de configuration pour ne plus jamais perdre un job et offrir une expérience utilisateur parfaite. C'est ça, la magie de Laravel.
A lire
Autres articles de la même catégorie
Rejoignez-nous au Forum PHP 2025
Retrouvez l'équipe de Laravel France au Forum PHP 2025 !
Mathieu De Gracia
Inertia 2.0 : L'infinite scroll enfin simple
Inertia 2.0 débarque avec une fonctionnalité que tout le monde attendait : l'infinite scroll natif. Tout est maintenant intégré, simple, et ça fonctionne out of the box.
Ludovic Guénet 🪃
AFUP Day 2026 : Partagez votre expertise Laravel !
L’AFUP Day 2026 revient dans quatre villes françaises, une occasion unique de monter sur scène et présenter vos idées et projets !
Mathieu De Gracia