{"id":396,"date":"2025-08-27T20:58:11","date_gmt":"2025-08-27T20:58:11","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=396"},"modified":"2025-08-27T20:58:13","modified_gmt":"2025-08-27T20:58:13","slug":"how-to-use-laravel-horizon-for-queue-monitoring","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/how-to-use-laravel-horizon-for-queue-monitoring\/","title":{"rendered":"How to Use Laravel Horizon for Queue Monitoring"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>How to Use Laravel Horizon for Queue Monitoring<\/strong><\/h2>\n\n\n\n<p>When your Laravel app uses queues to handle heavy workloads (emails, reports, notifications), monitoring those jobs becomes essential. <strong>Laravel Horizon<\/strong> provides a beautiful dashboard to manage, monitor, and scale Redis-based queues. In this guide, we\u2019ll install Horizon, configure it, run workers, and explore key features for monitoring high-performance apps.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>1 &#8211; Install Horizon<\/strong><\/h2>\n\n\n\n<p>Horizon works with Redis queues, so ensure your app uses <code>QUEUE_CONNECTION=redis<\/code>. Then install Horizon:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">composer require laravel\/horizon\nphp artisan horizon:install\nphp artisan migrate<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This installs Horizon\u2019s migrations for monitoring job batches and failed jobs. Horizon also publishes a config file for customizing queues and balancing.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2 &#8211; Running Horizon<\/strong><\/h2>\n\n\n\n<p>Start Horizon just like a queue worker, but with its own dashboard and balancing features:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">php artisan horizon<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>By default, Horizon runs workers and exposes a dashboard at <code>\/horizon<\/code>. It automatically restarts workers after code changes, unlike <code>queue:work<\/code>.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3 &#8211; Horizon Dashboard<\/strong><\/h2>\n\n\n\n<p>Visit <code>\/horizon<\/code> in your app to see job metrics. Horizon shows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Current and recent jobs<\/li>\n<li>Failed jobs<\/li>\n<li>Processing times<\/li>\n<li>Throughput and retries<\/li>\n<li>Which worker processed each job<\/li>\n<\/ul>\n\n\n\n<p>This visibility helps diagnose bottlenecks\u2014like a failing job blocking a queue or an overloaded worker pool. For background on queues, see <a href=\"\/blog\/how-to-use-laravel-queues-for-faster-performance\">How to Use Laravel Queues for Faster Performance<\/a>.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>4 &#8211; Configuring Supervisors<\/strong><\/h2>\n\n\n\n<p>Horizon uses <strong>supervisors<\/strong> to manage how many workers are assigned to a queue. Configure them in <code>config\/horizon.php<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ config\/horizon.php (snippet)<\/span>\n<span class=\"hljs-string\">'supervisors'<\/span> =&gt; &#91;\n    <span class=\"hljs-string\">'app-supervisor'<\/span> =&gt; &#91;\n        <span class=\"hljs-string\">'connection'<\/span> =&gt; <span class=\"hljs-string\">'redis'<\/span>,\n        <span class=\"hljs-string\">'queue'<\/span> =&gt; &#91;<span class=\"hljs-string\">'default'<\/span>, <span class=\"hljs-string\">'emails'<\/span>],\n        <span class=\"hljs-string\">'balance'<\/span> =&gt; <span class=\"hljs-string\">'auto'<\/span>,\n        <span class=\"hljs-string\">'minProcesses'<\/span> =&gt; <span class=\"hljs-number\">2<\/span>,\n        <span class=\"hljs-string\">'maxProcesses'<\/span> =&gt; <span class=\"hljs-number\">10<\/span>,\n        <span class=\"hljs-string\">'tries'<\/span> =&gt; <span class=\"hljs-number\">3<\/span>,\n    ],\n],\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This supervisor auto-scales between 2\u201310 workers depending on queue load. The <code>balance<\/code> setting dynamically adjusts worker counts for optimal throughput.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>5 &#8211; Monitoring Failed Jobs<\/strong><\/h2>\n\n\n\n<p>Horizon makes it easy to retry failed jobs directly from the dashboard. You can also configure alerts for specific job failures.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Providers\/HorizonServiceProvider.php<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Providers<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Support<\/span>\\<span class=\"hljs-title\">ServiceProvider<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Laravel<\/span>\\<span class=\"hljs-title\">Horizon<\/span>\\<span class=\"hljs-title\">Horizon<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HorizonServiceProvider<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">ServiceProvider<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">boot<\/span><span class=\"hljs-params\">()<\/span>: <span class=\"hljs-title\">void<\/span>\n    <\/span>{\n        Horizon::routeMailNotificationsTo(<span class=\"hljs-string\">'admin@example.com'<\/span>);\n        Horizon::routeSlackNotificationsTo(<span class=\"hljs-string\">'slack-webhook-url'<\/span>);\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This configures Horizon to send notifications when jobs fail repeatedly. You can use mail, Slack, or custom notification channels for alerts.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>6 &#8211; Horizon and High Concurrency<\/strong><\/h2>\n\n\n\n<p>In high-traffic apps, Horizon works well with <a href=\"\/blog\/optimizing-laravel-for-high-concurrency-with-octane\">Octane<\/a>. Octane reduces response latency, while Horizon balances and monitors background job throughput. Together they keep both request handling and background tasks efficient.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>Laravel Horizon gives you visibility and control over queued jobs. We installed Horizon, ran the dashboard, configured supervisors, and set up alerts. With Horizon, Redis queues become not only powerful but also transparent\u2014helping you scale workloads confidently. Pair Horizon with Octane and Redis caching for maximum performance under heavy load.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s Next<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/how-to-use-laravel-queues-for-faster-performance\">How to Use Laravel Queues for Faster Performance<\/a> \u2014 foundational guide before adding Horizon.<\/li>\n<li><a href=\"\/blog\/caching-strategies-in-laravel-redis-vs-database-vs-file\">Caching Strategies in Laravel: Redis vs Database vs File<\/a> \u2014 Redis powers Horizon queues and cache.<\/li>\n<li><a href=\"\/blog\/using-laravel-telescope-to-debug-performance-issues\">Using Laravel Telescope to Debug Performance Issues<\/a> \u2014 monitor requests and jobs alongside Horizon.<\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>How to Use Laravel Horizon for Queue Monitoring When your Laravel app uses queues to handle heavy workloads (emails, reports, notifications), monitoring those jobs becomes essential. Laravel Horizon provides a beautiful dashboard to manage, monitor, and scale Redis-based queues. In this guide, we\u2019ll install Horizon, configure it, run workers, and explore key features for monitoring [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":400,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[69,44,65],"class_list":["post-396","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-horizon","tag-performance","tag-queues"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/396","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=396"}],"version-history":[{"count":1,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/396\/revisions"}],"predecessor-version":[{"id":399,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/396\/revisions\/399"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/400"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}