laravel-queue-monitor maintained by jaydeep
Laravel Queue Monitor
Monitor your Laravel queues at a glance. Laravel Queue Monitor records the full lifecycle of every queued job and shows you pending, running, completed, and failed jobs — from an Artisan command or a live web dashboard.
Laravel ships with failed_jobs (failed) and a jobs table (pending, database
driver only), but it never stores completed jobs. This package fills that gap
by subscribing to Laravel's queue events and persisting each job's lifecycle to
a dedicated queue_monitor table — so it works with any queue driver
(database, Redis, SQS, …).
Screenshots
The live dashboard with stat cards and the recent-jobs table.
Queued (pending) jobs:

Completed & failed jobs:

Requirements
- PHP 7.4 – 8.4
- Laravel 8 – 12
Installation
From Packagist
composer require jaydeep/laravel-queue-monitor
Local development (path repository)
If you are working on the package from a local checkout, add a path repository
to your application's composer.json before requiring it:
"repositories": [
{
"type": "path",
"url": "./laravel-queue-monitor",
"options": { "symlink": true }
}
]
composer require jaydeep/laravel-queue-monitor:^1.0
Publish and migrate
The service provider is auto-discovered. Publish and run the migration:
php artisan vendor:publish --tag=queue-monitor-migrations
php artisan migrate
Optionally publish the config and views:
php artisan vendor:publish --tag=queue-monitor-config
php artisan vendor:publish --tag=queue-monitor-views
Usage
Artisan command
php artisan queue-monitor:show
Queue Monitor
+---------+---------+-----------+--------+-------+
| Pending | Running | Completed | Failed | Total |
+---------+---------+-----------+--------+-------+
| 3 | 1 | 128 | 2 | 134 |
+---------+---------+-----------+--------+-------+
Options:
| Option | Description |
|---|---|
--json |
Output the full snapshot as JSON |
--limit=N |
Number of recent jobs to list |
--prune |
Delete records older than the configured retention hours |
--json returns a machine-readable snapshot:
{
"counts": {
"pending": 3, "queued": 2, "running": 1,
"completed": 128, "failed": 2, "total": 134
},
"recent": [
{
"id": 134, "name": "App\\Jobs\\SendInvoice", "queue": "default",
"connection": "redis", "status": "completed", "attempts": 1,
"duration_ms": 412, "queued_at": "2026-07-10 09:15:01",
"started_at": "2026-07-10 09:15:02", "finished_at": "2026-07-10 09:15:02",
"exception": null
}
],
"generated_at": "2026-07-10 09:20:00"
}
Web dashboard
Visit /queue-monitor in your browser for a live, auto-refreshing,
responsive Bootstrap 5 dashboard with stat cards and a paginated recent
jobs table (Prev / Next). It polls /queue-monitor/stats on the interval set in
config; the stat cards always reflect global totals while the table is paged.
The stats endpoint accepts pagination query parameters:
GET /queue-monitor/stats?page=2&per_page=15
Response shape:
{
"counts": { "pending": 3, "running": 1, "completed": 128, "failed": 2, "total": 134 },
"recent": [ /* current page of jobs */ ],
"pagination": { "current_page": 2, "per_page": 15, "total": 134, "last_page": 9, "from": 16, "to": 30 },
"generated_at": "2026-07-10 09:20:00"
}
Security: the dashboard uses the
webmiddleware group by default. Before exposing it in production, add authentication/authorization middleware inconfig/queue-monitor.php(route.middleware), e.g.['web', 'auth'].
Configuration
config/queue-monitor.php:
| Key | Default | Description |
|---|---|---|
enabled |
true |
Master switch for lifecycle recording |
table |
queue_monitor |
Monitor table name |
connection |
null |
DB connection for the table (null = default) |
route.enabled |
true |
Enable the web dashboard routes |
route.prefix |
queue-monitor |
URL prefix for the dashboard |
route.middleware |
['web'] |
Middleware applied to the dashboard routes |
route.refresh |
5 |
Dashboard auto-refresh interval (seconds) |
recent_limit |
25 |
Recent jobs shown in the console command |
per_page |
15 |
Jobs per page on the web dashboard |
prune_after_hours |
72 |
Retention window used by --prune (null = keep) |
Each key is also driven by an environment variable — set QUEUE_MONITOR_ENABLED=false
to switch recording off without touching config, or QUEUE_MONITOR_ROUTE_ENABLED=false
to disable the dashboard routes.
How it works
The package registers a subscriber for Laravel's queue events:
| Event | Recorded status |
|---|---|
JobQueued |
queued |
JobProcessing |
running |
JobProcessed |
completed |
JobFailed |
failed |
Records are correlated by job id across events. All monitor writes are wrapped in a guard, so a monitoring error can never interrupt the job being processed.
queue_monitor table
| Column | Notes |
|---|---|
id |
Primary key |
job_id |
Driver job id (used to correlate events) |
name |
Resolved job class name |
connection, queue |
Where the job ran |
status |
queued / running / completed / failed |
attempts |
Attempt count at last update |
queued_at, started_at, finished_at |
Lifecycle timestamps |
duration_ms |
Processing time in milliseconds |
exception |
Full exception string for failed jobs |
created_at, updated_at |
Eloquent timestamps |
Querying in code
use Jaydeep\QueueMonitor\Models\MonitoredJob;
MonitoredJob::failed()->latest()->take(10)->get();
MonitoredJob::completed()->count();
MonitoredJob::pending()->get(); // queued + running
Testing
composer install
./vendor/bin/phpunit
License
MIT © Jaydeep Gadhiya