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.
| 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 |
- PHP 8.2, 8.3, or 8.4
- Laravel 11, 12, or 13
composer require crontinel/laravel
php artisan crontinel:installThat'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.
# 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-alertsExits with code 0 when all monitors are healthy, 1 if any alert is active. Use this in CI or monitoring pipelines.
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')],
],
];# 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-keyCrontinel 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.
Set horizon.enabled = false in config. Queue and cron monitoring work independently of Horizon.
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.
MIT — free forever. See LICENSE.
Built by Harun R Rayhan · crontinel.com