PHPackages                             smwks/laravel-zenith - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. smwks/laravel-zenith

ActiveLibrary[Database &amp; ORM](/categories/database)

smwks/laravel-zenith
====================

Laravel Horizon for database-backed queues — real-time dashboard and worker management for the database queue driver.

v0.2.6(1w ago)18207MITPHPPHP ^8.4CI failing

Since Feb 28Pushed 4w agoCompare

[ Source](https://github.com/smwks/laravel-zenith)[ Packagist](https://packagist.org/packages/smwks/laravel-zenith)[ Docs](https://github.com/smwks/laravel-zenith)[ GitHub Sponsors](https://github.com/ralphschindler)[ RSS](/packages/smwks-laravel-zenith/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (39)Versions (8)Used By (0)

 [![Zenith for Laravel](art/logo.png)](art/logo.png)

Zenith For Laravel
==================

[](#zenith-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/c2b0b98ee090b141a6a9e468ea1b80b2195a4f1beacfa9aeddee52dd168c357f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736d776b732f6c61726176656c2d7a656e6974682e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/smwks/laravel-zenith)[![GitHub Tests Action Status](https://camo.githubusercontent.com/0ebac74e3f20b577bba9d65c2a2a4e3adb5019274a16e74632aba931e6d985f6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f736d776b732f6c61726176656c2d7a656e6974682f72756e2d74657374732e796d6c3f6272616e63683d6d6173746572266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/smwks/laravel-zenith/actions?query=workflow%3Arun-tests+branch%3Amaster)[![Total Downloads](https://camo.githubusercontent.com/f4e5d26dfad05961e2078807718d4f9b278a8d2f63eea23970ea6ad68e0b11cb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f736d776b732f6c61726176656c2d7a656e6974682e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/smwks/laravel-zenith)

**Think Laravel Horizon, but for database-backed queues.** Zenith brings the same real-time visibility and worker management that Horizon provides for Redis — to the `database` queue driver.

If you're running queues out of your database and want a live dashboard, worker process management, and job lifecycle tracking without switching to Redis, Zenith is built for you. See pending, processing, completed, and failed jobs alongside the worker processes handling them. Scale workers up or down, terminate supervisors, retry failures in bulk, and track performance over time — all from your browser, all without leaving your application.

---

Quick Install
-------------

[](#quick-install)

```
composer require smwks/laravel-zenith
php artisan vendor:publish --tag="zenith-migrations"
php artisan migrate
```

Then visit `/zenith` in your browser. The dashboard is protected by the `auth` middleware by default.

Start workers with:

```
php artisan zenith:work --queue=default
```

Add the monitor to your scheduler in `routes/console.php`:

```
Schedule::command('zenith:monitor')->everyMinute();
```

---

Run A Demo
----------

[](#run-a-demo)

Spin up a fresh Laravel app with Zenith installed in under a minute:

```
# new Laravel app without auth scaffolding since Zenith doesn't require it
laravel new -n demo-laravel-zenith
cd demo-laravel-zenith

# install Zenith
composer require smwks/laravel-zenith

php artisan vendor:publish --tag="zenith-config"

# **NOTE:** now go to update config/zenith.php to disable auth middleware
# 'route' => [
#     'middleware' => ['web'], // remove 'auth' since this is a demo
# ],

# publish and run migrations
php artisan vendor:publish --tag="zenith-migrations"
php artisan migrate

# start the demo worker (which dispatches test jobs every 10 seconds)
php artisan zenith:work

# in a separate terminal, start the server
php artisan serve
```

Notes:

- `-n` in `laravel new` skips the default auth scaffolding since Zenith doesn't require it.
- With the above steps also update `zenith.php` config to remove `auth` from the middleware array.

Then browse to  to see the dashboard.

---

Features
--------

[](#features)

### Live Dashboard

[](#live-dashboard)

A real-time overview of your queue system refreshing every 5 seconds. At a glance: how many workers are active, how many are idle or stuck, jobs pending and completed today, average processing time, throughput (jobs/hour), and failure rate.

### Job Visibility Across the Full Lifecycle

[](#job-visibility-across-the-full-lifecycle)

Browse every stage of a job's journey across dedicated tabs:

- **Pending** — jobs waiting in the queue, filterable by queue name
- **Completed** — successful jobs with processing time and batch membership
- **Failed** — full exception messages, per-job retry and delete, bulk retry all
- **Batches** — batch progress bars, pending/failed counts, status at a glance

[![Jobs list](art/jobs-screenshot.png)](art/jobs-screenshot.png)

### Worker Management

[](#worker-management)

The Workers page shows the full supervisor/child process hierarchy. For each supervisor you see its queue, connection, worker count, total jobs processed, last heartbeat, and uptime. For each child worker you see individual job counts, health status, and a "Stuck" indicator when a heartbeat goes missing.

From the UI you can:

- **Scale Up** — spawn an additional child worker under a supervisor *(manual balance only)*
- **Scale Down** — remove a child worker gracefully *(manual balance only)*
- **Terminate** — send a shutdown signal to a supervisor

### Supervisor Groups &amp; Balance Strategies

[](#supervisor-groups--balance-strategies)

Each `zenith:work` invocation is tied to a named supervisor group defined in `config/zenith.php`. Groups configure the queue, connection, and — importantly — the balance strategy:

StrategyBehaviour`fixed`Workers start at `min_workers` and stay there. Scale Up/Down hidden in the UI. Ideal for Kubernetes pods or any environment where the process supervisor controls scale.`manual`Workers start at `min_workers`. Scale Up/Down buttons are visible in the dashboard. Operator-driven scaling within `min_workers`/`max_workers` bounds.`automatic`Workers start at `min_workers` and scale to demand on every heartbeat tick. Scale target is `ceil(pending_jobs / jobs_per_worker)`, clamped to `min_workers`/`max_workers`. Scales up to target immediately; scales down one step per tick only when the queue is empty.[![Workers list](art/workers-screenshot.png)](art/workers-screenshot.png)

### Heartbeat-Based Health Monitoring

[](#heartbeat-based-health-monitoring)

Every worker reports a heartbeat on a configurable interval (default: 30 seconds). The `zenith:monitor` command — run every minute via the scheduler — compares last heartbeat times against a configurable stuck threshold (default: 120 seconds). Workers that go silent are marked terminated; jobs held by those workers can be automatically released back to the queue.

### Job Lifecycle Events

[](#job-lifecycle-events)

Zenith hooks into Laravel's job events to record a `JobEvent` at every transition: `started`, `completed`, `failed`, `retried`, `cancelled`. Each event captures the queue, connection, attempt count, and processing time. The event log is the foundation for metrics, audit trails, and debugging.

### API

[](#api)

All dashboard data is also available via JSON endpoints under `/zenith/api/` — useful for external monitoring systems or custom tooling.

EndpointDescription`GET /zenith/api/metrics`Full metrics snapshot`GET /zenith/api/metrics/workers`Worker counts`GET /zenith/api/metrics/jobs`Job counts`GET /zenith/api/metrics/performance`Throughput and timing`GET /zenith/api/metrics/queues`Per-queue pending counts`GET /zenith/api/workers`Worker list`GET /zenith/api/workers/{id}`Worker detail`GET /zenith/api/jobs`Pending jobs`GET /zenith/api/jobs-history`Completed/cancelled jobs`GET /zenith/api/jobs-failed`Failed jobs`DELETE /zenith/api/jobs/{id}`Cancel a pending job`POST /zenith/api/jobs/{id}/retry`Retry a failed job`POST /zenith/api/jobs/retry-all`Retry all failed jobs### Built-In Test Dispatcher

[](#built-in-test-dispatcher)

The Tests tab dispatches real jobs through your queue so you can verify the full stack is wired up correctly. Dispatch a single job or a batch of configurable size, with optional logging enabled, and watch them flow through the dashboard in real time.

---

Installation
------------

[](#installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require smwks/laravel-zenith
```

### 2. Publish and Run Migrations

[](#2-publish-and-run-migrations)

```
php artisan vendor:publish --tag="zenith-migrations"
php artisan migrate
```

This creates three tables: `zenith_processes`, `zenith_history`, and `zenith_events`.

### 3. Publish the Config (optional)

[](#3-publish-the-config-optional)

```
php artisan vendor:publish --tag="zenith-config"
```

### 4. Publish the Views (optional)

[](#4-publish-the-views-optional)

```
php artisan vendor:publish --tag="zenith-views"
```

---

Artisan Commands
----------------

[](#artisan-commands)

### `zenith:work`

[](#zenithwork)

The primary worker command. Replaces `queue:work` with full Zenith monitoring.

```
php artisan zenith:work --queue=default --name=my-worker
```

OptionDefaultDescription`--name``default`Supervisor group name — must match a key in `config('zenith.supervisors')` to pick up its balance strategy and worker bounds`--queue`Comma-separated queue names (overrides the group's configured queue)`--memory``128`Memory limit in MB`--timeout``60`Max seconds a job may run`--sleep``3`Seconds to sleep when queue is empty`--tries``1`Max attempts before a job is failed`--backoff``0`Seconds to wait between retries`--max-jobs``0`Stop after processing this many jobs (0 = unlimited)`--max-time``0`Stop after this many seconds (0 = unlimited)`--stop-when-empty`Stop when the queue is drained`--force`Run even in maintenance mode### `zenith:monitor`

[](#zenithmonitor)

Detects stuck workers and optionally releases their held jobs back to the queue. Run this every minute via the scheduler.

```
php artisan zenith:monitor
php artisan zenith:monitor --auto-retry
```

### `zenith:prune`

[](#zenithprune)

Removes old records to keep the database lean. Safe to schedule daily.

```
php artisan zenith:prune
php artisan zenith:prune --completed=7 --failed=30 --events=7
```

OptionDefaultDescription`--completed``7`Days to retain completed job history`--failed``30`Days to retain failed job records`--events``7`Days to retain job events`--all`Prune all types at once using config defaults---

Configuration
-------------

[](#configuration)

```
// config/zenith.php
return [

    // Master switch — disable to stop all monitoring without removing the package
    'enabled' => env('ZENITH_ENABLED', true),

    'route' => [
        'domain'     => env('ZENITH_ROUTE_DOMAIN', null),      // restrict dashboard to a specific domain
        'prefix'     => env('ZENITH_ROUTE_PREFIX', 'zenith'),
        'middleware' => ['web', 'auth'],
    ],

    // Named supervisor groups — each `zenith:work --name=X` invocation reads from its group
    'supervisors' => [
        'default' => [
            'connection'      => env('QUEUE_CONNECTION', 'database'),
            'queue'           => 'default',
            'balance'         => env('ZENITH_BALANCE', 'fixed'),      // fixed | manual | automatic
            'min_workers'     => env('ZENITH_MIN_WORKERS', 1),
            'max_workers'     => env('ZENITH_MAX_WORKERS', 1),
            'jobs_per_worker' => env('ZENITH_JOBS_PER_WORKER', 5),    // automatic balance only
        ],
    ],

    // How often workers report their heartbeat (seconds)
    'heartbeat_interval' => env('ZENITH_HEARTBEAT_INTERVAL', 30),

    // How long without a heartbeat before a worker is considered stuck (seconds)
    'stuck_job_threshold' => env('ZENITH_STUCK_JOB_THRESHOLD', 120),

    // Automatically release stuck jobs back to the queue
    'auto_retry_stuck_jobs' => env('ZENITH_AUTO_RETRY_STUCK_JOBS', false),

    'retention' => [
        'completed_jobs' => env('ZENITH_RETAIN_COMPLETED_JOBS', 7),
        'failed_jobs'    => env('ZENITH_RETAIN_FAILED_JOBS', 30),
        'job_events'     => env('ZENITH_RETAIN_JOB_EVENTS', 7),
    ],

    // Override the database connection used by Zenith tables
    'database_connection' => env('ZENITH_DB_CONNECTION', null),

];
```

Multiple named groups are supported — useful when different queues need different strategies:

```
'supervisors' => [
    'default' => [
        'queue'       => 'default',
        'balance'     => 'fixed',
        'min_workers' => 2,
        'max_workers' => 2,
    ],
    'high-priority' => [
        'queue'           => 'high,default',
        'balance'         => 'automatic',
        'min_workers'     => 1,
        'max_workers'     => 8,
        'jobs_per_worker' => 10,
    ],
],
```

Then start each group as a separate process:

```
php artisan zenith:work --name=default
php artisan zenith:work --name=high-priority
```

---

Recommended Scheduler Setup
---------------------------

[](#recommended-scheduler-setup)

```
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('zenith:monitor')->everyMinute();
Schedule::command('zenith:prune --all')->daily();
```

---

How It Works
------------

[](#how-it-works)

### Process Model

[](#process-model)

`zenith:work` starts a **supervisor** process that manages a pool of **child worker** processes. Each child runs `queue:work` under the hood. The supervisor monitors its children and respawns them if they exit, and listens for scaling instructions delivered via the heartbeat action column in the database.

### Heartbeats

[](#heartbeats)

On every worker loop iteration, Zenith updates `last_heartbeat_at` in the `zenith_processes` table for both the worker and its supervisor. `zenith:monitor` compares these timestamps against `stuck_job_threshold` and marks unresponsive processes as terminated. If `auto_retry_stuck_jobs` is enabled, any job the stuck worker was holding gets released back to the queue automatically.

### Job Events

[](#job-events)

Zenith registers listeners for Laravel's built-in job lifecycle events:

Laravel EventZenith Action`JobProcessing`Records a `started` event, marks worker as `working``JobProcessed`Records a `completed` event, writes `JobHistory`, marks worker `idle`, increments `jobs_completed``JobFailed`Records a `failed` event, captures exception, writes `JobHistory`, increments `jobs_failed`Each `JobHistory` record stores the full payload, processing time in milliseconds, attempt count, queue, and connection. The `JobEvent` log provides the per-transition audit trail that drives the dashboard metrics.

### Dashboard Metrics

[](#dashboard-metrics)

The `MetricsService` computes all metrics on demand from the Zenith tables:

- **Active workers** — processes with status `idle` or `working`
- **Completed today** — `JobHistory` records with `completed_at` today
- **Jobs per hour** — `completed` events in the last 60 minutes
- **Failure rate** — `(failed / (failed + completed)) * 100` over the same window
- **Avg processing time** — mean of `processing_time_ms` from today's completed jobs

---

Testing
-------

[](#testing)

```
composer test
```

---

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for recent changes.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Ralph Schindler](https://github.com/ralphschindler)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance94

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~22 days

Recently: every ~28 days

Total

6

Last Release

10d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9c4a15cb4e97bc39a3aea8304fb04d56c0d753f2a6b79c83db0a894647ba8de7?d=identicon)[ralphschindler](/maintainers/ralphschindler)

---

Top Contributors

[![ralphschindler](https://avatars.githubusercontent.com/u/76674?v=4)](https://github.com/ralphschindler "ralphschindler (30 commits)")

---

Tags

databaselaravelqueueslaravelsmwkslaravel-zenith

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/smwks-laravel-zenith/health.svg)

```
[![Health](https://phpackages.com/badges/smwks-laravel-zenith/health.svg)](https://phpackages.com/packages/smwks-laravel-zenith)
```

###  Alternatives

[illuminate/database

The Illuminate Database package.

2.8k54.9M11.6k](/packages/illuminate-database)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M132](/packages/laravel-pulse)[tallstackui/tallstackui

TallStackUI is a powerful suite of Blade components that elevate your workflow of Livewire applications.

725172.4k14](/packages/tallstackui-tallstackui)[bavix/laravel-wallet

It's easy to work with a virtual wallet.

1.3k1.3M19](/packages/bavix-laravel-wallet)[wnx/laravel-backup-restore

A package to restore database backups made with spatie/laravel-backup.

213420.1k2](/packages/wnx-laravel-backup-restore)[filament/support

Core helper methods and foundation code for all Filament packages.

2331.0M245](/packages/filament-support)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
