Laravel Horizon: Supervisor Tuning &amp; Scaling in Production | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Laravel Horizon: Queue Metrics, Supervisor Tuning, and Graceful Scaling in Production

 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 without dropping jobs in a high-throughput Laravel application.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 25 Jul 2026 · Updated 25 Jul 2026 · 3 min read

ShareCopy linkCopied

 ![Laravel Horizon: Queue Metrics, Supervisor Tuning, and Graceful Scaling in Production](https://cdn.msaied.com/469/ebbc461b808da425a418bf6ffc998d7a.png) 

  On this page +1. [Beyond the Pretty Dashboard](#beyond-the-pretty-dashboard)
2. [Supervisor Configuration That Actually Matters](#supervisor-configuration-that-actually-matters)
3. [balance Modes](#codebalancecode-modes)
4. [Reading Horizon Metrics Programmatically](#reading-horizon-metrics-programmatically)
5. [Graceful Worker Termination](#graceful-worker-termination)
6. [Scaling Horizon Itself: Multiple Supervisors](#scaling-horizon-itself-multiple-supervisors)
7. [Deployment Without Dropping Jobs](#deployment-without-dropping-jobs)
8. [Key Takeaways](#key-takeaways)

 Beyond the Pretty Dashboard
---------------------------

Most teams install Horizon, glance at the dashboard, and call it done. That's leaving serious reliability and throughput on the table. Horizon's real value is in its supervisor model, its Redis-backed metrics, and the levers it exposes for graceful scaling — none of which are obvious from the UI alone.

---

Supervisor Configuration That Actually Matters
----------------------------------------------

Horizon's `config/horizon.php` `environments` block is where production behaviour is defined. The defaults are conservative; here's a production-grade starting point:

```php
'production' => [
    'supervisor-default' => [
        'connection'  => 'redis',
        'queue'       => ['critical', 'default', 'low'],
        'balance'     => 'auto',
        'minProcesses' => 2,
        'maxProcesses' => 20,
        'balanceMaxShift' => 3,   // max workers added/removed per cycle
        'balanceCooldown' => 3,   // seconds between rebalance attempts
        'tries'       => 3,
        'timeout'     => 90,
        'nice'        => 0,
    ],
],

```

### `balance` Modes

| Mode | Behaviour | |---|---| | `simple` | Splits `maxProcesses` evenly across queues | | `auto` | Scales per-queue based on workload ratio | | `false` | Fixed process count, no autoscaling |

`auto` is almost always correct for mixed-priority workloads. The `balanceMaxShift` cap prevents Horizon from spawning 15 workers in one cycle and overwhelming your database connection pool.

---

Reading Horizon Metrics Programmatically
----------------------------------------

The dashboard shows throughput and wait times, but you can query the same data in code for alerting or custom dashboards:

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

$metrics = app(MetricsRepository::class);

// Throughput (jobs/minute) for a queue
$throughput = $metrics->throughputForQueue('critical');

// Average runtime in milliseconds
$runtime = $metrics->runtimeForQueue('critical');

// Snapshot history (last 24 two-minute windows)
$snapshots = $metrics->snapshotsForQueue('critical');

```

Wire these into a scheduled command that pushes to your APM or fires a Slack alert when `runtimeForQueue` exceeds your SLA threshold. Horizon stores snapshots in Redis sorted sets, so reads are O(log n) and cheap.

---

Graceful Worker Termination
---------------------------

Horizon sends `SIGTERM` to workers when you deploy. Workers finish their current job and exit — but only if `timeout` is set correctly. A job that runs longer than `timeout` is killed mid-execution.

Rule: `timeout` in `horizon.php` must be **less than** the PHP process timeout (`max_execution_time`) and less than the queue connection's `retry_after`.

```php
// config/queue.php
'redis' => [
    'driver'       => 'redis',
    'retry_after'  => 120, // seconds before job is re-queued
    ...
],

// config/horizon.php supervisor
'timeout' => 90, // must be < retry_after

```

If `timeout >= retry_after`, a slow job gets re-queued while still running, causing duplicate execution.

---

Scaling Horizon Itself: Multiple Supervisors
--------------------------------------------

For heterogeneous workloads, use multiple named supervisors rather than one catch-all:

```php
'production' => [
    'supervisor-heavy' => [
        'queue'        => ['pdf-generation', 'video-processing'],
        'balance'      => 'auto',
        'minProcesses' => 1,
        'maxProcesses' => 5,
        'timeout'      => 300,
    ],
    'supervisor-fast' => [
        'queue'        => ['notifications', 'webhooks'],
        'balance'      => 'auto',
        'minProcesses' => 5,
        'maxProcesses' => 30,
        'timeout'      => 30,
    ],
],

```

This prevents a backlog of slow PDF jobs from starving your notification queue. Each supervisor manages its own process pool independently.

---

Deployment Without Dropping Jobs
--------------------------------

```bash
# In your deploy script — order matters
php artisan horizon:pause   # stop accepting new jobs
sleep 5                      # let in-flight jobs finish
php artisan horizon:terminate
# deploy code
php artisan horizon:publish  # re-publish assets if updated
sudo supervisord restart horizon

```

`horizon:pause` sets a Redis flag; workers check it between jobs and idle rather than pick up new work. This gives you a clean drain window without `SIGKILL`.

---

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

- Set `balanceMaxShift` and `balanceCooldown` to prevent thundering-herd autoscaling.
- Always keep `timeout` &lt; `retry_after` to avoid duplicate job execution.
- Use multiple named supervisors to isolate slow queues from fast ones.
- Query `MetricsRepository` programmatically for SLA alerting, not just the UI.
- Drain workers with `horizon:pause` before `horizon:terminate` on every deploy.

- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [horizon](https://www.msaied.com/public/articles?search=horizon)
- [queues](https://www.msaied.com/public/articles?search=queues)
- [production](https://www.msaied.com/public/articles?search=production)
- [performance](https://www.msaied.com/public/articles?search=performance)

 Frequently asked questions 
---------------------------

  Why do my jobs run twice after deploying with Horizon?This is almost always a timeout/retry\_after mismatch. If your supervisor `timeout` equals or exceeds the queue connection's `retry\_after`, Redis re-queues the job before the worker finishes it. Set `timeout` to at least 30 seconds less than `retry\_after`.

   When should I use multiple Horizon supervisors instead of one?Use separate supervisors when queues have significantly different job durations or throughput requirements. A single supervisor with `balance=auto` will still share its process pool across all queues, meaning slow jobs can starve fast ones. Separate supervisors give each queue class its own dedicated pool with independent scaling limits.

   Can I access Horizon metrics outside the dashboard for custom alerting?Yes. Bind `Laravel\\Horizon\\Contracts\\MetricsRepository` from the container and call `throughputForQueue`, `runtimeForQueue`, or `snapshotsForQueue`. These read from Redis sorted sets and are safe to call in a scheduled command or health-check endpoint.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

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

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleMulti-Tenant SaaS with Laravel + Filament: Scoping Queries, Panels, and Jobs per Tenant](https://www.msaied.com/public/articles/multi-tenant-saas-with-laravel-filament-scoping-queries-panels-and-jobs-per-tenant) [Next articleLaravel Queues in Production: Horizon Tuning, Metrics, and Graceful Scaling](https://www.msaied.com/public/articles/laravel-queues-in-production-horizon-tuning-metrics-and-graceful-scaling)  

   On this page
-------------

1. [Beyond the Pretty Dashboard](#beyond-the-pretty-dashboard)
2. [Supervisor Configuration That Actually Matters](#supervisor-configuration-that-actually-matters)
3. [balance Modes](#codebalancecode-modes)
4. [Reading Horizon Metrics Programmatically](#reading-horizon-metrics-programmatically)
5. [Graceful Worker Termination](#graceful-worker-termination)
6. [Scaling Horizon Itself: Multiple Supervisors](#scaling-horizon-itself-multiple-supervisors)
7. [Deployment Without Dropping Jobs](#deployment-without-dropping-jobs)
8. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/743/8998fac3a41451ab3fe1588194e17a43.png) Filament · 3 min read### Securing Filament Plugins with Plumb: Automated Security Scoring for PHP Packages

5 Oct 2026 ](https://www.msaied.com/public/articles/securing-filament-plugins-with-plumb-automated-security-scoring-for-php-packages) [ ![](https://cdn.msaied.com/742/2d02018669cdeedccb5de2efb898f0ee.png) Filament · 3 min read### Filament v3.3.56 Released: File Hash Names and Livewire Upload Fix

5 Oct 2026 ](https://www.msaied.com/public/articles/filament-v3356-released-file-hash-names-and-livewire-upload-fix) [ ![](https://cdn.msaied.com/741/5b55c123ad08e4d34e1f4b99ad6a428b.png)  · 3 min read### Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API

5 Oct 2026 ](https://www.msaied.com/public/articles/filament-v4-schema-based-forms-infolists-and-the-unified-schema-api-5) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
