Laravel 12.34 a introduit l’une des fonctionnalités les plus attendues de l’année : les Deferred Batches, tant pour les requêtes HTTP que pour les files d’attente. Derrière ce nom technique se cache une révolution dans la gestion des tâches asynchrones lourdes : exécuter des dizaines, voire des centaines de requêtes ou de jobs sans bloquer l’utilisateur, avec un suivi précis des progrès, des succès et des échecs.
Cette nouveauté, portée par Wendell Adriel et validée par Taylor Otwell, est déjà saluée comme "le meilleur ajout à Laravel depuis les queues" par la communauté sur X. Plongeons dans les détails techniques, avec un exemple complet et une explication pas à pas.
Qu’est-ce que les Deferred Batches ?
Un Deferred Batch est un lot de tâches (HTTP ou jobs) qui :
- S’exécute en arrière-plan (via une file d’attente),
- Ne bloque jamais la réponse HTTP principale,
- Permet de suivre en temps réel :
- Le nombre de tâches terminées,
- Les échecs,
- La progression globale,
- Offre des callbacks personnalisés sur
then,catch,finally.
Avant : Vous deviez gérer manuellement les jobs, les progress bars, les retries…
Maintenant : Laravel fait tout ça en une seule méthode.
1. Http::batch() – Des Requêtes HTTP en Lot, Différées
Cas d’usage classique
Vous devez appeler 50 API externes (Stripe, GitHub, CRM, etc.) pour synchroniser des données utilisateur.
Problème : 50 appels synchrones = 10+ secondes de latence → timeout ou UX dégradée.
Solution : Http::batch() + file d’attente.
Exemple Complet
1use Illuminate\Support\Facades\Http;2use Illuminate\Bus\Batch;3use Illuminate\Support\Facades\Bus;45// Dans un contrôleur ou un job6public function syncExternalApis()7{8 $batch = Http::batch([12 // ... 47 autres requêtes13 ])->dispatch(); // ← Différé dans la queue !1415 // Sauvegarder l'ID du batch pour suivi16 session()->put('sync_batch_id', $batch->id);1718 return redirect()->route('sync.status')19 ->with('message', 'Synchronisation lancée en arrière-plan...');20}1use Illuminate\Support\Facades\Http;2use Illuminate\Bus\Batch;3use Illuminate\Support\Facades\Bus;45// Dans un contrôleur ou un job6public function syncExternalApis()7{8 $batch = Http::batch([12 // ... 47 autres requêtes13 ])->dispatch(); // ← Différé dans la queue !1415 // Sauvegarder l'ID du batch pour suivi16 session()->put('sync_batch_id', $batch->id);1718 return redirect()->route('sync.status')19 ->with('message', 'Synchronisation lancée en arrière-plan...');20}
Suivi de la progression (dans une vue ou API)
1// routes/web.php2Route::get('/sync/status', function () {3 $batchId = session('sync_batch_id');45 $batch = Bus::findBatch($batchId);67 if ($batch->finished()) {8 return "Terminé ! {$batch->processedRequests()} / {$batch->totalRequests} réussies.";9 }1011 return "En cours... {$batch->processedPercentage()}%";12});1// routes/web.php2Route::get('/sync/status', function () {3 $batchId = session('sync_batch_id');45 $batch = Bus::findBatch($batchId);67 if ($batch->finished()) {8 return "Terminé ! {$batch->processedRequests()} / {$batch->totalRequests} réussies.";9 }1011 return "En cours... {$batch->processedPercentage()}%";12});
Callbacks Puissants
1Http::batch([...])2 ->then(function (Batch $batch) {3 // Toutes les requêtes ont réussi4 Log::info('Sync complet !', ['processed' => $batch->processedRequests()]);5 })6 ->catch(function (Batch $batch, Throwable $e) {7 // Au moins une a échoué8 Notification::send(Admin::all(), new SyncFailed($batch));9 })10 ->finally(function (Batch $batch) {11 // Nettoyage, envoi d'email, etc.12 cache()->forget('sync_in_progress');13 })14 ->dispatch();1Http::batch([...])2 ->then(function (Batch $batch) {3 // Toutes les requêtes ont réussi4 Log::info('Sync complet !', ['processed' => $batch->processedRequests()]);5 })6 ->catch(function (Batch $batch, Throwable $e) {7 // Au moins une a échoué8 Notification::send(Admin::all(), new SyncFailed($batch));9 })10 ->finally(function (Batch $batch) {11 // Nettoyage, envoi d'email, etc.12 cache()->forget('sync_in_progress');13 })14 ->dispatch();
2. Deferred Queues – Jobs Différés en Batch
Même principe, mais pour n’importe quel job Laravel.
Exemple : Traitement de 1000 PDFs
1use Illuminate\Support\Facades\Bus;2use App\Jobs\GeneratePdfReport;34$batch = Bus::batch([5 new GeneratePdfReport($user1),6 new GeneratePdfReport($user2),7 // ... 998 autres8])->then(function (Batch $batch) {9 // Tous les PDFs sont générés11})->catch(function (Batch $batch, Throwable $e) {12 // Un job a échoué → retry ou alerte13 retryFailedJobs($batch);14})->dispatch();1use Illuminate\Support\Facades\Bus;2use App\Jobs\GeneratePdfReport;34$batch = Bus::batch([5 new GeneratePdfReport($user1),6 new GeneratePdfReport($user2),7 // ... 998 autres8])->then(function (Batch $batch) {9 // Tous les PDFs sont générés11})->catch(function (Batch $batch, Throwable $e) {12 // Un job a échoué → retry ou alerte13 retryFailedJobs($batch);14})->dispatch();
Priorité et Délai
1Bus::batch([...])2 ->priority(10) // Priorité dans la queue3 ->delay(now()->addMinutes(5)) // Démarrer dans 5 min4 ->dispatch();1Bus::batch([...])2 ->priority(10) // Priorité dans la queue3 ->delay(now()->addMinutes(5)) // Démarrer dans 5 min4 ->dispatch();
Fonctionnalités Clés des Deferred Batches
| Fonctionnalité | Description |
|---|---|
dispatch() |
Envoie le batch dans la queue (asynchrone) |
then(), catch(), finally() |
Callbacks sur succès/échec/complétion |
progress() |
Pourcentage en temps réel |
allowFailures() |
Continue même si une tâche échoue |
name('Sync Users') |
Nom pour debugging dans Horizon |
onQueue('high') |
File d’attente dédiée |
Intégration avec Laravel Horizon (Dashboard)
Dans Horizon, vous verrez :
- Un onglet Batches,
- Progression en temps réel,
- Boutons Retry, Cancel, Delete,
- Graphiques de performance.
1php artisan horizon1php artisan horizon
Pourquoi c’est une Révolution ?
| Avant (Laravel 11) | Après (Laravel 12.34) |
|---|---|
Http::pool() → synchrone ou limité |
Http::batch() → 100+ appels asynchrones |
| Jobs manuels + progress bars custom | Batch natif avec callbacks |
| Pas de suivi centralisé | Horizon + Bus::findBatch() |
| Risque de timeout | Zéro impact sur la réponse HTTP |
Mise à Jour & Compatibilité
1composer require laravel/framework:^12.341composer require laravel/framework:^12.34
Aucun breaking change. Fonctionne avec Redis, SQS, Database, Beanstalkd.
Assurez-vous que votre driver de queue supporte les batches (tous les drivers officiels le font).
Use Cases Réels
- Synchronisation CRM → 500 appels API → 3 secondes au lieu de 45.
- Génération de rapports mensuels → 10 000 jobs → suivi en dashboard.
- Import CSV massif → chunk par chunk, avec progression live.
- Webhooks en masse → retry automatique sur échec.
Conclusion
Avec Deferred Batches, Laravel 12.34 transforme une tâche complexe (gérer des centaines d’opérations asynchrones) en quelques lignes de code élégantes.
Taylor Otwell sur X :
"Deferred HTTP Batches & Queues – this is the cool stuff that shipped in the last two weeks."
→ 600+ likes, 120 retweets.
À vous de jouer : testez Http::batch()->dispatch() dans votre prochain projet. Votre utilisateur ne verra plus jamais une page qui charge…
Liens utiles :