studio/novacron
NovaCron is a Laravel Nova package for working with cron schedules. It helps you inspect scheduled tasks and cron expressions from your Nova dashboard, making it easier to monitor timing and keep job schedules organized. Use it to review upcoming runs and improve schedule visibility without leaving...
Novacron is a Nova tool that surfaces your Laravel scheduler (app/Console/Kernel.php, or routes/console.php on newer apps) inside the Nova admin panel so you can see, toggle, and run scheduled tasks without SSHing into the box. Treat it as a UI over schedule:list plus a small persistence layer for enable/disable state and run history.
Minimal setup:
composer require studio/novacron
php artisan vendor:publish --provider="Studio\Novacron\NovacronServiceProvider"
php artisan migrate
Register the tool in app/Providers/NovaServiceProvider.php:
public function tools()
{
return [
new \Studio\Novacron\Novacron(),
];
}
Then verify with php artisan nova:list or by hitting /nova and looking for the tool in the sidebar.
Where to look first:
config/novacron.php — enabled/disabled default, table names, permission gate.app/Console/Kernel.php (schedule() method) — this is the source of truth for what appears in the UI. Anything not defined here won't show up.crons / run-log tables exist before debugging "nothing shows".First useful use case: open the tool, confirm your existing tasks are listed with their CRON expressions and next-due timestamps, then disable one non-critical task from the UI and watch that schedule:run skips it. This is usually the fastest sanity check that the package is wired correctly.
Caveat up front: the repository is archived with a small star count and no dependents. Read this as a starting point or a reference implementation, not a maintained dependency. Pin the version in composer.json and plan for a fork if you adopt it.
Keep the scheduler declarative and discoverable. Novacron reads the schedule definition, so avoid dynamic loops and closures that hide task identity:
// Good — shows up cleanly in Novacron with a stable name
$schedule->command('reports:daily')->dailyAt('02:00')->withoutOverlapping();
$schedule->job(new PruneStaleSessions)->hourly()->onOneServer();
// Bad — opaque in the UI, hard to toggle, hard to log
foreach (config('reports.targets') as $t) {
$schedule->call(fn () => $t->run())->everyMinute();
}
Name your commands (protected $signature = 'reports:daily';) and prefer ->command() / ->job() over ->call() so the tool can attach meaningful labels and per-run state.
Gate the tool by role, not by hiding it. Novacron is powerful — toggling a task off can silently break billing or backups. Wire the package into Nova's authorization:
// AuthServiceProvider
Gate::define('manage-schedules', fn (User $u) => $u->hasRole('ops'));
Then reference the same ability in your NovaServiceProvider tool registration or the package config, depending on which hook the version exposes. If the version doesn't support config-level gating, wrap it:
Nova::tools(fn () => auth()->user()?->can('manage-schedules')
? [new \Studio\Novacron\Novacron()]
: []);
Use the run log as your first debugging surface. When a task "doesn't run", check the package's history table before storage/logs:
php artisan tinker
>>> DB::table('novacron_runs')->latest()->take(5)->get();
Compare against php artisan schedule:list (Laravel 8+) to confirm the task is actually registered and due. If the list matches but the log is empty, the problem is in the scheduler runner or your overlap lock, not the UI.
Pair it with a real watcher. Novacron is a control plane, not a monitor. Keep schedule:run under cron/systemd, and layer a heartbeat (Horizon, Healthchecks, Sentry cron monitors) on top:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
Team workflow pattern. Use Novacron during incidents: disable noisy tasks (e.g. a failing sync) to stop alert storms, fix the underlying issue, re-enable from the UI — all without a deploy. Document in your runbook which tasks are safe to toggle and which are gated behind the manage-schedules ability.
composer.json constraints in the repo before installing; if your Nova major version differs, expect to patch the tool class. If you adopt, fork it into your org and own it.->call() with closures, or built inside loops/conditionals, may render with generic labels or fail to toggle. If a task is missing from the UI, it's almost always because the schedule definition isn't statically resolvable.Kernel.php — otherwise the next deploy with a fresh DB (or a cache clear) reintroduces it, and someone will be confused by a "disabled in code, enabled in Nova" mismatch.config('app.timezone') unless you call ->timezone(). The UI may display times in the server zone while your operators think in local time. Verify with schedule:list before trusting the displayed "next run".withoutOverlapping() and onOneServer() require a shared cache driver (Redis/Memcached/DB). Novacron's toggle state lives in your DB — make sure all nodes point at the same database, or the "disabled" flag will only apply to whichever node serves the Nova request. Use onOneServer() on the schedule mutex, not just the cache.php artisan nova:publish and config:clear after adding the tool. A blank panel is usually a missing published asset or an unrun migration, not a bug in the package.composer update and makes your fork diffable. If you need scheduled-task management today with an actively maintained option, the Laravel schedule:list output, laravel/schedule-monitor, or a small custom Nova resource over Schedule::events() are reasonable replacements.php artisan schedule:list shows the task; (2) crontab -l has the schedule:run entry; (3) app timezone matches expectations; (4) overlap lock isn't stuck (cache:clear the mutex key); (5) the Novacron toggle is actually on. Most incidents resolve at step 1 or 2.How can I help you explore Laravel packages today?