Laravel Horizon: Queue Tuning &amp; Graceful Scaling | 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 in Production: Horizon Tuning, Metrics, and Graceful Scaling        On this page       1. [  Laravel Horizon in Production: Beyond the Defaults ](#laravel-horizon-in-production-beyond-the-defaults)
2. [  Supervisor Configuration That Reflects Reality ](#supervisor-configuration-that-reflects-reality)
3. [  Reading Horizon Metrics Without Guessing ](#reading-horizon-metrics-without-guessing)
4. [  Handling Backpressure Without Losing Jobs ](#handling-backpressure-without-losing-jobs)
5. [  Graceful Shutdown: The Part Everyone Gets Wrong ](#graceful-shutdown-the-part-everyone-gets-wrong)
6. [  Takeaways ](#takeaways)

  ![Laravel Queues in Production: Horizon Tuning, Metrics, and Graceful Scaling](https://cdn.msaied.com/470/afd2bee56d15842d72c1c6d5c238d236.png)

  #laravel   #horizon   #queues   #performance   #production  

 Laravel Queues in Production: Horizon Tuning, Metrics, and Graceful Scaling 
=============================================================================

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

       Table of contents

1. [  01   Laravel Horizon in Production: Beyond the Defaults  ](#laravel-horizon-in-production-beyond-the-defaults)
2. [  02   Supervisor Configuration That Reflects Reality  ](#supervisor-configuration-that-reflects-reality)
3. [  03   Reading Horizon Metrics Without Guessing  ](#reading-horizon-metrics-without-guessing)
4. [  04   Handling Backpressure Without Losing Jobs  ](#handling-backpressure-without-losing-jobs)
5. [  05   Graceful Shutdown: The Part Everyone Gets Wrong  ](#graceful-shutdown-the-part-everyone-gets-wrong)
6. [  06   Takeaways  ](#takeaways)

 Laravel Horizon in Production: Beyond the Defaults
--------------------------------------------------

Most teams install Horizon, push the default config, and move on. That works until traffic spikes, jobs pile up, and the dashboard turns red. This article focuses on the levers that actually matter: supervisor balancing strategies, metric-driven scaling decisions, and graceful shutdown patterns that prevent job loss.

---

Supervisor Configuration That Reflects Reality
----------------------------------------------

Horizon's `config/horizon.php` ships with a single supervisor block. In production you almost always need multiple supervisors — one per logical job class or priority tier.

```php
'production' => [
    'supervisor-critical' => [
        'connection' => 'redis',
        'queue'      => ['critical'],
        'balance'    => 'auto',
        'minProcesses' => 2,
        'maxProcesses' => 10,
        'tries'      => 3,
        'timeout'    => 30,
        'nice'       => 0,
    ],
    'supervisor-default' => [
        'connection' => 'redis',
        'queue'      => ['default', 'notifications'],
        'balance'    => 'simple',
        'processes'  => 4,
        'tries'      => 5,
        'timeout'    => 90,
        'nice'       => 10, // lower OS priority than critical
    ],
    'supervisor-bulk' => [
        'connection' => 'redis',
        'queue'      => ['bulk-exports'],
        'balance'    => 'auto',
        'minProcesses' => 1,
        'maxProcesses' => 3,
        'balanceMaxShift'  => 1,
        'balanceCooldown'  => 5,
        'timeout'    => 600,
        'nice'       => 15,
    ],
],

```

**Key decisions here:**

- `balance => auto` lets Horizon shift processes between queues in the supervisor dynamically. Use it when queue depths fluctuate.
- `balanceMaxShift` limits how many processes can be added or removed per rebalance cycle — prevents thrashing.
- `nice` maps to the Unix process priority. Bulk jobs should yield CPU to critical ones.
- Separate `timeout` per supervisor. A 600-second timeout on the critical supervisor would mask hung jobs.

---

Reading Horizon Metrics Without Guessing
----------------------------------------

Horizon stores rolling throughput and runtime snapshots in Redis. You can query them programmatically:

```php
use Laravel\Horizon\Contracts\MetricsRepository;

$metrics = app(MetricsRepository::class);

$throughput = $metrics->throughputForQueue('default');  // jobs/min
$runtime    = $metrics->runtimeForQueue('default');     // avg ms

```

Pipe these into your observability stack (Datadog, Prometheus via a custom exporter, or even a simple scheduled command that writes to a log channel). Alert when throughput drops below your baseline or runtime climbs above your SLA threshold — not when the queue depth crosses an arbitrary number.

---

Handling Backpressure Without Losing Jobs
-----------------------------------------

When producers outpace consumers, the naive fix is "add more workers." The better fix is to model backpressure explicitly.

```php
// In a high-frequency dispatch path
use Illuminate\Support\Facades\Redis;

$depth = Redis::llen('queues:default');

if ($depth > 5000) {
    // Slow the producer, not just scale the consumer
    sleep(1); // or return a 429 to the upstream caller
}

Dispatch::dispatch(new ProcessWebhook($payload));

```

For HTTP-triggered jobs, returning a `202 Accepted` with a `Retry-After` header is more honest than silently queuing millions of jobs that will take hours to drain.

---

Graceful Shutdown: The Part Everyone Gets Wrong
-----------------------------------------------

Horizon sends `SIGTERM` to workers when you deploy. Workers finish their current job and exit — but only if your jobs respect the signal. Long-running jobs that ignore termination signals will be killed mid-execution.

```php
class ProcessLargeExport implements ShouldQueue
{
    public function handle(): void
    {
        foreach ($this->chunks() as $chunk) {
            if (app('queue.worker')->shouldQuit) {
                // Checkpoint state, re-dispatch remainder
                ProcessLargeExport::dispatch($this->remainingChunks());
                return;
            }

            $this->processChunk($chunk);
        }
    }
}

```

Set `HORIZON_TERMINATE_WAIT` (the `--stop-when-empty` equivalent) in your deploy script to give workers time to finish:

```bash
php artisan horizon:terminate
sleep 30  # match your longest expected job runtime
supervisorctl start horizon

```

---

Takeaways
---------

- Split supervisors by job priority and runtime profile, not just queue name.
- Use `balanceMaxShift` and `balanceCooldown` to prevent process thrashing under `auto` balance.
- Export Horizon metrics to your observability stack; alert on throughput and runtime, not raw depth.
- Model backpressure at the producer — slowing dispatch is safer than unbounded queue growth.
- Make long-running jobs checkpoint-aware so `SIGTERM` results in a safe re-dispatch, not data loss.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-queues-in-production-horizon-tuning-metrics-and-graceful-scaling&text=Laravel+Queues+in+Production%3A+Horizon+Tuning%2C+Metrics%2C+and+Graceful+Scaling) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-queues-in-production-horizon-tuning-metrics-and-graceful-scaling) 

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

  3 questions  

     Q01  When should I use `balance =&gt; auto` vs `balance =&gt; simple` in Horizon?        Use `auto` when a supervisor handles multiple queues with variable depth — Horizon will shift processes toward the busiest queue. Use `simple` for fixed-ratio allocation or single-queue supervisors where you want predictable process counts. 

      Q02  How do I prevent jobs from being lost during a Horizon restart on deploy?        Run `php artisan horizon:terminate` before starting the new release, and add a sleep in your deploy script equal to your longest expected job runtime. Ensure long-running jobs check `app('queue.worker')-&gt;shouldQuit` and checkpoint their state so they can safely re-dispatch remaining work. 

      Q03  Is it safe to run multiple Horizon instances across servers?        Yes. Each server runs its own Horizon process, and they coordinate through Redis. Ensure each server's `horizon.php` supervisor config reflects that server's role (e.g., bulk-export workers only on high-memory nodes) and that `APP_NAME` is unique per server if you want separate dashboard entries. 

  Continue reading

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

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

 [ ![Concurrency in Laravel: Process Pools, Fibers, and the Concurrency Facade](https://cdn.msaied.com/471/ba1a628c196e92cbb81033c865c9ad26.png) laravel concurrency php 

### Concurrency in Laravel: Process Pools, Fibers, and the Concurrency Facade

Laravel's Concurrency facade and process pools let you run independent work in parallel without reaching for a...

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

 26 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/concurrency-in-laravel-process-pools-fibers-and-the-concurrency-facade) [ ![Laravel Horizon: Queue Metrics, Supervisor Tuning, and Graceful Scaling in Production](https://cdn.msaied.com/469/ebbc461b808da425a418bf6ffc998d7a.png) laravel horizon queues 

### Laravel Horizon: Queue Metrics, Supervisor Tuning, and Graceful Scaling in Production

Beyond the dashboard: how to tune Horizon supervisors, interpret queue metrics, and scale workers gracefully w...

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

 25 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-horizon-queue-metrics-supervisor-tuning-and-graceful-scaling-in-production-1) [ ![Multi-Tenant SaaS with Laravel + Filament: Scoping Queries, Panels, and Jobs per Tenant](https://cdn.msaied.com/468/b3aaf636b79861b2a53a5f16e89f7253.png) laravel filament multi-tenancy 

### Multi-Tenant SaaS with Laravel + Filament: Scoping Queries, Panels, and Jobs per Tenant

A practical deep-dive into building a multi-tenant SaaS on Laravel and Filament v3/v4: tenant resolution, auto...

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

 25 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/multi-tenant-saas-with-laravel-filament-scoping-queries-panels-and-jobs-per-tenant) 

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