Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Horizon Prometheus Exporter Laravel Package

lkaemmerling/laravel-horizon-prometheus-exporter

Expose Laravel Horizon queue metrics to Prometheus for monitoring and alerting. Track jobs, queues, wait times, throughput, and worker health via a scrapeable endpoint, making it easy to visualize Horizon performance in Grafana and catch backlog or failure issues early.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require lkaemmerling/laravel-horizon-prometheus-exporter. The service provider is auto-discovered; on Laravel 13.x you need v1.8.3 or later (that is the only change in this release — a compatibility bump, no API changes).
  • The exporter is a reader, not a producer: it assumes Laravel Horizon is already installed, configured, and has been running long enough to populate its Redis-backed repositories. Confirm php artisan horizon:status reports running before debugging the exporter.
  • Publish the config file first (php artisan vendor:publish and pick the package's config tag — check the README for the exact tag in your version) and read it top to bottom. It is small and controls the route path, middleware, and which collectors run.
  • Verify by hand before touching Prometheus: curl -s https://your-app.test/horizon/metrics | head -50. You should see Prometheus text exposition format (# HELP, # TYPE, metric_name{labels} value). If you get HTML or a 302, it is a routing/auth problem, not a metrics problem.
  • First useful use case: a single Grafana panel per queue showing processed rate, failed rate, and current waiting jobs, with one alert on failed increasing. That is 90% of the value of this package and takes an afternoon.

Implementation Patterns

  • Scrape config: point Prometheus (or Grafana Agent / VictoriaMetrics / a hosted collector) at the endpoint with an explicit metrics_path, a scrape_interval of 30–60s, and credentials if you protect the route. Keep it in the same job group as your other Laravel exporters so timestamps line up in dashboards.
  • Protect the endpoint. Metrics reveal queue names, throughput, and failure volumes. Put it behind your existing auth middleware, a bearer-token middleware, or an IP allowlist at the ingress. Do this before the first production deploy, not after.
  • Environment gating: enable the route in production/staging only, or disable it in config/horizon-prometheus-exporter.php per environment. Local metrics are usually noise because Horizon often is not running on dev machines.
  • Multi-process / multi-host awareness: if you run PHP-FPM with several workers or several app servers behind a load balancer, decide deliberately whether to scrape one instance or all. Horizon's state is centralized in Redis, so every replica reports the same numbers — scraping all of them double-counts in sum() aggregations.
  • Alerting recipes that work well with the Horizon metric families:
    • rate(<failed_jobs_total>[5m]) > 0 per queue for immediate failure alerts.
    • max_over_time(<waiting_jobs>[10m]) > N for backlog alerts, scoped by queue label.
    • Wait-time alerts rather than raw job counts for latency SLOs — queue depth alone produces noisy pages on bursty workloads.
  • Coexistence with other exporters: if you already export HTTP/DB metrics via a generic Laravel Prometheus package, keep naming and label conventions aligned (queue, connection) so a single Grafana variable can drive every panel.
  • Deploy smoke test: after release, curl the endpoint with the production token from CI and fail the pipeline on a non-200. Route/auth regressions after a Laravel upgrade are the most common breakage, and this catches them in minutes.

Gotchas and Tips

  • Redis is the hidden dependency. Horizon stores everything in Redis; if the connection is down, misconfigured, or pointed at a different database than Horizon uses, you get empty metrics or a 500 — not an obvious "Redis unavailable" error. Cross-check config/horizon.php's use connection against the exporter's config.
  • Empty output is usually "Horizon has not run", not a bug. A freshly deployed app with no jobs will expose zeros or nothing at all. Generate a job or two before concluding the package is broken.
  • Scrapes are not free. Each request walks Horizon's repositories in Redis. A 1-second scrape interval on a large fleet will show up in Redis CPU. 30–60s is the right default.
  • Cardinality creep: queue names are a fine label; job class names, tags, or payload-derived values are not. If you extend the collectors, resist adding high-cardinality labels — Prometheus will happily ingest them until it doesn't.
  • Duplicate-registration panics: the underlying prometheus_client_php registry throws if you register the same metric name twice. If you add custom collectors, reuse the package's registry rather than constructing a second one, and guard against double registration inOctane/long-running workers.
  • Octane and persistent workers: state that survives between requests can leak counters across scrapes. If you run Octane, verify counters behave (compare two consecutive scrapes) before trusting rate calculations.
  • Config caching: after editing the config, run php artisan config:clear (and re-cache in deploy). A stale cached route path is a classic 404-after-deploy cause.
  • Debugging order: php artisan route:list | grep -i metric → check middleware → curl -v with and without credentials → storage/logs/laravel.log → php artisan horizon:status. That sequence resolves nearly every report.
  • Upgrading: v1.8.3 is a non-breaking compatibility release for Laravel 13.x. If you are on Laravel 12 or earlier, there is no reason to rush, but there is also no migration cost — pin ^1.8.3 if you plan to move to 13.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource