harunrrayhan / crontinel
Background job and cron monitoring for Laravel. Monitors Horizon internals, queue depth, and cron health.
Requires
- php: ^8.2|^8.3|^8.4
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/queue: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
This package is not auto-updated.
Last update: 2026-04-07 09:05:48 UTC
README
Background job and cron monitoring for Laravel. Monitors Horizon internals, queue depth, and cron health — things generic monitors can't see.
Cronitor tells you a job ran. Crontinel tells you your Horizon supervisor is paused.
What it monitors
| Monitor | What it sees |
|---|---|
| Horizon | Supervisor status per supervisor (not just "Horizon is running"), paused state, failed jobs per minute |
| Queues | Depth per queue, failed count, oldest job age — Redis and database drivers |
| Cron jobs | Every scheduled command run: exit code, duration, late detection |
Requirements
- PHP 8.2, 8.3, or 8.4
- Laravel 11, 12, or 13
Installation
composer require harunrrayhan/crontinel php artisan crontinel:install
That's it. Visit /crontinel in your browser.
crontinel:install publishes the config file and runs the migration for the crontinel_runs table.
Cron run tracking is automatic — Crontinel listens to Laravel's ScheduledTaskFinished and ScheduledTaskFailed events. No wrapping or modification of your scheduled commands needed.
CLI health check
# Table output (human-readable) php artisan crontinel:check # JSON output (for CI/CD integration) php artisan crontinel:check --format=json # Check without firing alerts php artisan crontinel:check --no-alerts
Exits with code 0 when all monitors are healthy, 1 if any alert is active. Use this in CI or monitoring pipelines.
Configuration
After install, edit config/crontinel.php:
return [ // Dashboard URL path (default: /crontinel) 'path' => env('CRONTINEL_PATH', 'crontinel'), // Dashboard middleware 'middleware' => ['web', 'auth'], // Connect to Crontinel SaaS for multi-app hosted dashboards (optional) 'saas_key' => env('CRONTINEL_API_KEY'), 'saas_url' => env('CRONTINEL_API_URL', 'https://app.crontinel.com'), 'horizon' => [ 'enabled' => true, 'supervisor_alert_after_seconds' => 60, 'failed_jobs_per_minute_threshold' => 5, 'connection' => 'horizon', // Redis connection name for Horizon ], 'queues' => [ 'enabled' => true, 'watch' => [], // empty = auto-discover 'depth_alert_threshold' => 1000, 'wait_time_alert_seconds' => 300, ], 'cron' => [ 'enabled' => true, 'late_alert_after_seconds' => 120, 'retain_days' => 30, ], 'alerts' => [ 'channel' => env('CRONTINEL_ALERT_CHANNEL'), // 'slack' or 'mail' 'mail' => ['to' => env('CRONTINEL_ALERT_EMAIL')], 'slack' => ['webhook_url' => env('CRONTINEL_SLACK_WEBHOOK')], ], ];
Environment variables
# Dashboard path (optional) CRONTINEL_PATH=crontinel # Alerts — set channel to 'slack' or 'mail' CRONTINEL_ALERT_CHANNEL=slack CRONTINEL_SLACK_WEBHOOK=https://hooks.slack.com/... CRONTINEL_ALERT_EMAIL=ops@yourcompany.com # SaaS reporting (optional) CRONTINEL_API_KEY=your-api-key
Alerts
Crontinel fires alerts when:
- Horizon is stopped or paused
- A supervisor process goes down
- Failed jobs per minute exceeds threshold
- Queue depth or oldest job age exceeds threshold
- A scheduled command exits with non-zero code
- A scheduled command is late (missed its expected run window)
Alerts auto-resolve and send a "resolved" notification when the issue clears.
Alert deduplication: The same alert won't fire more than once per 5 minutes for the same issue.
Not using Horizon?
Set horizon.enabled = false in config. Queue and cron monitoring work independently of Horizon.
Connecting to Crontinel SaaS
The OSS package works standalone. To get multi-app hosted dashboards, longer history, and team access, visit crontinel.com to join the early access list.
License
MIT — free forever. See LICENSE.
Built by Harun R Rayhan · crontinel.com