Laravel Job Batching, Chaining &amp; Rate Limiting | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues        On this page       1. [  Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues ](#job-batching-chaining-and-rate-limited-middleware-in-laravel-queues)
2. [  Batches: Parallel Work With a Shared Lifecycle ](#batches-parallel-work-with-a-shared-lifecycle)
3. [  Chains: Sequential Pipelines With Shared Context ](#chains-sequential-pipelines-with-shared-context)
4. [  Rate-Limited Job Middleware ](#rate-limited-job-middleware)
5. [  Takeaways ](#takeaways)

  ![Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues](https://cdn.msaied.com/167/07cf94b1aa8fcead662b9cd5af47acb6.png)

  #laravel   #queues   #jobs   #async  

 Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues 
=======================================================================

     14 Jun 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues  ](#job-batching-chaining-and-rate-limited-middleware-in-laravel-queues)
2. [  02   Batches: Parallel Work With a Shared Lifecycle  ](#batches-parallel-work-with-a-shared-lifecycle)
3. [  03   Chains: Sequential Pipelines With Shared Context  ](#chains-sequential-pipelines-with-shared-context)
4. [  04   Rate-Limited Job Middleware  ](#rate-limited-job-middleware)
5. [  05   Takeaways  ](#takeaways)

 Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues
---------------------------------------------------------------------

Laravel's queue system is deceptively deep. Most teams dispatch individual jobs and call it done. But production workflows demand composition: run a set of jobs in parallel, then trigger a follow-up only when all succeed, and never hammer a third-party API faster than its rate limit allows. Laravel gives you all three primitives — batches, chains, and job middleware — and combining them correctly is where the real power lives.

---

### Batches: Parallel Work With a Shared Lifecycle

A batch dispatches multiple jobs concurrently and exposes callbacks for completion, failure, and progress.

```php
use Illuminate\Support\Facades\Bus;

$batch = Bus::batch([
    new ProcessInvoice($invoice1),
    new ProcessInvoice($invoice2),
    new ProcessInvoice($invoice3),
])
->then(fn (Batch $batch) => SendBatchSummary::dispatch($batch->id))
->catch(fn (Batch $batch, Throwable $e) => Log::error('Batch failed', [
    'batch' => $batch->id,
    'error' => $e->getMessage(),
]))
->finally(fn (Batch $batch) => Cache::forget('invoices:processing'))
->name('Invoice Processing')
->allowFailures() // don't cancel remaining jobs on a single failure
->dispatch();

```

Store `$batch->id` if you need to poll progress from a UI. `$batch->progress()` returns 0–100 based on processed job count.

**Important:** Every job in a batch must use the `Batchable` trait, and you should check `$this->batch()->cancelled()` at the start of `handle()` to respect early cancellation.

```php
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessInvoice implements ShouldQueue
{
    use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle(): void
    {
        if ($this->batch()?->cancelled()) {
            return;
        }

        // ... process
    }
}

```

---

### Chains: Sequential Pipelines With Shared Context

Chains execute jobs one after another; if any job fails, the rest are abandoned.

```php
Bus::chain([
    new ValidateOrder($order),
    new ChargePayment($order),
    new FulfillOrder($order),
    new SendConfirmationEmail($order),
])
->catch(fn (Throwable $e) => $order->markFailed($e->getMessage()))
->dispatch();

```

You can mix batches inside chains for hybrid workflows:

```php
Bus::chain([
    new PrepareExport($report),
    Bus::batch([
        new ExportChunk($report, 0),
        new ExportChunk($report, 1),
        new ExportChunk($report, 2),
    ]),
    new MergeExportChunks($report),
])->dispatch();

```

This pattern — prepare, fan-out in parallel, then merge — is a clean map-reduce for queue workers.

---

### Rate-Limited Job Middleware

Throttling at the job level is far more reliable than sleeping inside `handle()`. Laravel's `RateLimited` middleware uses the cache to enforce limits across all workers.

```php
use Illuminate\Queue\Middleware\RateLimited;

class SyncToStripe implements ShouldQueue
{
    public function middleware(): array
    {
        return [new RateLimited('stripe-sync')];
    }
}

```

Define the limiter in a service provider:

```php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('stripe-sync', fn () =>
    Limit::perMinute(60)->response(fn () =>
        // job is released back to the queue automatically
        null
    )
);

```

When the limit is hit, the job is released back with a calculated backoff — no wasted worker time, no dropped requests.

For per-tenant limits, key the limiter dynamically:

```php
public function middleware(): array
{
    return [new RateLimited('stripe-sync:' . $this->tenantId)];
}

```

---

### Takeaways

- Use `Bus::batch()` for parallel fan-out; always add `Batchable` and check for cancellation.
- Use `Bus::chain()` for sequential pipelines where order and dependency matter.
- Nest a batch inside a chain for map-reduce style workflows.
- Throttle third-party API jobs with `RateLimited` middleware — never `sleep()`.
- Key rate limiters per tenant or resource to avoid cross-tenant interference.
- Monitor batch progress via `$batch->id` and expose it to your UI for long-running operations.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fjob-batching-chaining-and-rate-limited-middleware-in-laravel-queues&text=Job+Batching%2C+Chaining%2C+and+Rate-Limited+Middleware+in+Laravel+Queues) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fjob-batching-chaining-and-rate-limited-middleware-in-laravel-queues) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  What happens to a chain if one job in a nested batch fails?        By default, a single failure in a batch cancels the batch and prevents subsequent chain steps from running. Use `-&gt;allowFailures()` on the batch if you want remaining batch jobs to continue, but note the chain's `catch` callback will still fire if the batch itself is marked as failed. 

      Q02  Does rate-limited middleware work across multiple Horizon workers?        Yes. The `RateLimited` middleware uses your configured cache driver as the shared counter, so limits are enforced globally across all worker processes and servers — as long as they share the same cache backend (Redis is recommended). 

      Q03  Can I track batch progress in a Filament or Livewire UI?        Yes. Store the batch ID in your database or session after dispatching, then poll `Bus::findBatch($id)` on a Livewire component using a `wire:poll` directive. The `$batch-&gt;progress()` method returns an integer 0–100 you can bind directly to a progress bar. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Eloquent Custom Casts: Encapsulating Value Objects Without the Bloat](https://cdn.msaied.com/174/2c75896ee4182bb2f66e2c93bed18796.png) laravel eloquent ddd 

### Eloquent Custom Casts: Encapsulating Value Objects Without the Bloat

Custom Eloquent casts let you bind rich value objects directly to model attributes. This article shows how to...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 14 Jun 2026     1 min read  

  Read    

 ](https://msaied.com/articles/eloquent-custom-casts-encapsulating-value-objects-without-the-bloat) [ ![Filament v4 Schema-Based Forms: Unified Schema API in Practice](https://cdn.msaied.com/173/6e0d9faa9137cb296e37831c3645e7ba.png) filament laravel filament-v4 

### Filament v4 Schema-Based Forms: Unified Schema API in Practice

Filament v4 replaces scattered form/infolist definitions with a single Schema API. This post walks through rea...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 14 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/filament-v4-schema-based-forms-unified-schema-api-in-practice) [ ![The Pipeline Pattern in Laravel: Building Custom Pipelines Beyond Middleware](https://cdn.msaied.com/172/a5dea5e84a6eab22d5d7a76869aaecb4.png) laravel design-patterns pipeline 

### The Pipeline Pattern in Laravel: Building Custom Pipelines Beyond Middleware

Laravel's Pipeline class is far more than the engine behind HTTP middleware. Learn how to compose reusable, te...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 14 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/the-pipeline-pattern-in-laravel-building-custom-pipelines-beyond-middleware) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
