Laravel Queue Backpressure &amp; Dead-Letter Queues | 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)    Laravel Queues at Scale: Backpressure, Dead-Letter Queues, and Graceful Degradation        On this page       1. [  The Problem Nobody Talks About ](#the-problem-nobody-talks-about)
2. [  Backpressure: Slowing the Producer ](#backpressure-slowing-the-producer)
3. [  Measuring Queue Depth Before Dispatching ](#measuring-queue-depth-before-dispatching)
4. [  Dead-Letter Queues: Isolating Poison Pills ](#dead-letter-queues-isolating-poison-pills)
5. [  Routing Exhausted Jobs to a DLQ ](#routing-exhausted-jobs-to-a-dlq)
6. [  Graceful Degradation: Shedding Load Intentionally ](#graceful-degradation-shedding-load-intentionally)
7. [  Observability Glue ](#observability-glue)
8. [  Key Takeaways ](#key-takeaways)

  ![Laravel Queues at Scale: Backpressure, Dead-Letter Queues, and Graceful Degradation](https://cdn.msaied.com/602/fcffaaa5442f84486d6059eaa4106d26.png)

  #laravel   #queues   #reliability   #backend   #scalability  

 Laravel Queues at Scale: Backpressure, Dead-Letter Queues, and Graceful Degradation 
=====================================================================================

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

       Table of contents

1. [  01   The Problem Nobody Talks About  ](#the-problem-nobody-talks-about)
2. [  02   Backpressure: Slowing the Producer  ](#backpressure-slowing-the-producer)
3. [  03   Measuring Queue Depth Before Dispatching  ](#measuring-queue-depth-before-dispatching)
4. [  04   Dead-Letter Queues: Isolating Poison Pills  ](#dead-letter-queues-isolating-poison-pills)
5. [  05   Routing Exhausted Jobs to a DLQ  ](#routing-exhausted-jobs-to-a-dlq)
6. [  06   Graceful Degradation: Shedding Load Intentionally  ](#graceful-degradation-shedding-load-intentionally)
7. [  07   Observability Glue  ](#observability-glue)
8. [  08   Key Takeaways  ](#key-takeaways)

 The Problem Nobody Talks About
------------------------------

Most Laravel queue tutorials stop at `php artisan queue:work`. That is fine for low-traffic apps, but once you have burst traffic — a flash sale, a viral email campaign, a cron that fans out 50,000 jobs — you need three things your default setup does not give you: **backpressure**, **dead-letter isolation**, and **graceful degradation**.

---

Backpressure: Slowing the Producer
----------------------------------

Backpressure means the producer (the HTTP request or command that dispatches jobs) slows down when the queue is already overwhelmed. Without it, a spike fills Redis memory and workers fall further behind.

### Measuring Queue Depth Before Dispatching

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

final class ThrottledDispatcher
{
    private const MAX_DEPTH = 5_000;

    public function dispatch(ShouldQueue $job, string $queue = 'default'): void
    {
        $depth = (int) Redis::llen('queues:' . $queue);

        if ($depth >= self::MAX_DEPTH) {
            throw new QueueSaturatedException(
                "Queue '{$queue}' depth {$depth} exceeds limit."
            );
        }

        dispatch($job)->onQueue($queue);
    }
}

```

In an HTTP context you can catch `QueueSaturatedException` and return HTTP 503 with a `Retry-After` header. For internal fan-out commands, log the saturation and skip non-critical jobs.

---

Dead-Letter Queues: Isolating Poison Pills
------------------------------------------

Laravel's `failed_jobs` table is a dead-letter store, but it is a single flat table. When a job fails repeatedly it keeps consuming worker time on retries. A better pattern is a dedicated **dead-letter queue** that workers never touch automatically.

### Routing Exhausted Jobs to a DLQ

```php
use Throwable;
use Illuminate\Queue\InteractsWithQueue;

class ProcessOrderExport implements ShouldQueue
{
    use InteractsWithQueue;

    public int $tries = 3;
    public int $backoff = 60;

    public function failed(Throwable $e): void
    {
        // Re-queue onto a monitored DLQ instead of only logging
        dispatch(new DeadLetterJob(
            originalClass: static::class,
            payload: $this->order->id,
            reason: $e->getMessage(),
        ))->onQueue('dead-letter');
    }
}

```

`DeadLetterJob` itself never retries (`$tries = 1`) and simply persists a record to a `dead_letter_events` table with full context. A Filament resource or a nightly alert then surfaces these for human review.

---

Graceful Degradation: Shedding Load Intentionally
-------------------------------------------------

Not every job is equal. Sending a transactional email is critical; regenerating a report thumbnail is not. Tag jobs with a priority tier and shed low-priority work under load.

```php
enum QueueTier: string
{
    case Critical = 'critical';
    case Standard = 'default';
    case Background = 'background';
}

class RegenerateThumbnail implements ShouldQueue
{
    public string $queue = QueueTier::Background->value;
    public int $tries = 1; // shed silently on failure
}

```

In `config/horizon.php` (or your supervisor config) assign more workers to `critical`, fewer to `background`, and set `--stop-when-empty` on background workers during incidents:

```php
'environments' => [
    'production' => [
        'supervisor-critical' => [
            'queue' => 'critical',
            'processes' => 10,
            'balance' => 'auto',
        ],
        'supervisor-background' => [
            'queue' => 'background',
            'processes' => 2,
            'balance' => 'simple',
        ],
    ],
],

```

During a degraded incident you can temporarily scale `supervisor-background` processes to zero via the Horizon API or a feature flag without touching critical workers.

---

Observability Glue
------------------

None of this works without metrics. Emit a gauge from a scheduled command:

```php
Schedule::call(function () {
    foreach (['critical', 'default', 'background', 'dead-letter'] as $q) {
        $depth = (int) Redis::llen('queues:' . $q);
        Metric::gauge('queue.depth', $depth, ['queue' => $q]);
    }
})->everyMinute();

```

Alert when `dead-letter` depth grows or `critical` depth exceeds your SLA threshold.

---

Key Takeaways
-------------

- **Backpressure** protects Redis and gives callers a clear signal to back off; return 503 from HTTP, skip from CLI.
- **Dead-letter queues** isolate poison-pill jobs so they do not starve healthy workers on retries.
- **Tier your queues** and assign worker counts per tier so you can shed background load without touching critical paths.
- **Metrics on queue depth** per named queue are non-negotiable in production; alert before the backlog becomes a crisis.
- Keep `DeadLetterJob` simple and non-retrying — its only job is durable persistence for human triage.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-queues-at-scale-backpressure-dead-letter-queues-and-graceful-degradation&text=Laravel+Queues+at+Scale%3A+Backpressure%2C+Dead-Letter+Queues%2C+and+Graceful+Degradation) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-queues-at-scale-backpressure-dead-letter-queues-and-graceful-degradation) 

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

  2 questions  

     Q01  Does Laravel's built-in failed\_jobs table replace a dead-letter queue?        It covers the storage part, but failed_jobs does not prevent exhausted jobs from consuming retry attempts before landing there. A dedicated DLQ pattern routes jobs there immediately after the final failure, keeping your main queues clean and giving you a single place to monitor and replay problematic jobs. 

      Q02  How do I replay jobs from a dead-letter queue safely?        Store enough context in your dead_letter_events table (original class, serialized payload, failure reason, timestamp) to reconstruct and re-dispatch the original job. Add a Filament action or artisan command that deserializes the payload, instantiates the job, and dispatches it back to the original queue — optionally with a flag to skip the DLQ on the next failure so you can investigate interactively. 

  Continue reading

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

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

 [ ![whereBinary(): How to Run Case-Sensitive MySQL Queries in Laravel 13.27](https://cdn.msaied.com/600/0c7655400b43d3b85d1d1e9d0f4c8094.png) Laravel MySQL Query Builder 

### whereBinary(): How to Run Case-Sensitive MySQL Queries in Laravel 13.27

Laravel 13.27 adds whereBinary(), orWhereBinary(), whereNotBinary(), and orWhereNotBinary() — clean query-buil...

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

 26 Aug 2026     4 min read  

  Read    

 ](https://msaied.com/articles/wherebinary-how-to-run-case-sensitive-mysql-queries-in-laravel-1327) [ ![Compile PHP to Native Binaries with TypePHP](https://cdn.msaied.com/599/a0eb0516fcca2a7c2e83f4aabf206988.png) TypePHP AOT Compiler PHP Performance 

### Compile PHP to Native Binaries with TypePHP

The Swoole team has open-sourced TypePHP, an Ahead-Of-Time (AOT) compiler that translates PHP source code into...

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

 26 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/compile-php-to-native-binaries-with-typephp) [ ![State of Laravel 2026 Survey Is Now Open](https://cdn.msaied.com/601/bed3f2f014d6da639b118d2f03231e47.png) Laravel Survey Community 

### State of Laravel 2026 Survey Is Now Open

Tobias Petry has launched the State of Laravel 2026 survey — the sixth annual edition — covering developer pro...

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

 26 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/state-of-laravel-2026-survey-is-now-open) 

   [  ![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)
