Vous souhaitez nous soutenir ? Devenez sponsor de l'association sur notre page Github

Laravel 12 : Deferred Queue et Failover, les deux fonctionnalités qui changent tout

Publié le 13 novembre 2025 par Ludovic Guénet 🪃
Couverture de l'article 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.php
2'default' => env('QUEUE_CONNECTION', 'sync'),

Le flux d'exécution est prévisible mais problématique :

  1. L'utilisateur soumet le formulaire
  2. Le podcast est créé en base
  3. Le job lourd s'exécute (traitement, encodage, etc.)
  4. L'utilisateur attend...
  5. 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 :

  1. L'utilisateur soumet le formulaire
  2. Le podcast est créé en base
  3. La redirection s'effectue immédiatement
  4. 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 redirection
10 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 down
2$ sudo systemctl stop redis
3 
4# Les logs vous préviennent
5[WARNING] Redis connection failed, falling back to database
6 
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 database
2$ 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 migration
2$ php artisan queue:table
3 
4# Exécuter la migration
5$ 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 tinker
2>>> 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.

Ludovic Guénet 🪃 avatar
Ludovic Guénet 🪃
software engineer • mentor • bassist

A lire

Autres articles de la même catégorie