Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Scheduling Laravel Package

laravel-admin-ext/scheduling

Laravel-admin extension that adds a web UI for managing scheduled tasks: create, edit, enable or disable, run and monitor cron jobs from the admin panel instead of hand-editing the console kernel, with task logs for tracking results.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer in your laravel-admin project:

    composer require laravel-admin-ext/scheduling
    
  2. Register the extension in the admin panel:

    php artisan admin:import scheduling
    

    This creates the menu entry and wires the extension's routes/views into config/admin.php (extensions array). If your config is cached, run php artisan config:clear.

  3. Open the admin panel and look for the Scheduling menu item (typically under System or Helpers depending on your menu config). That page is the whole extension: a read-only table of every event in Illuminate\Console\Scheduling\Schedule, with expression, command, next/last run, and a Run button.

  4. Where to look first in your own code: app/Console/Kernel.php (or the schedule() method in routes/console.php / service providers on newer Laravel). That is the single source of truth the extension reflects over. Add a ->description('...') to a task, reload the page, and you'll see it render.

First use case: you've just written $schedule->command('reports:prune')->dailyAt('02:00'); and don't want to wait until 2 AM or fake the clock. Hit Run in the UI, watch the output, fix it, repeat. This is the package's core value — a manual trigger for scheduled jobs without SSH.

Implementation Patterns

Describe and name every task. The listing is only as useful as the metadata you give it. Always chain ->description(); prefer ->command('reports:prune') or ->job(...) over ->call(function () { ... }), because closures render as opaque strings and are often unrunnable from the UI.

$schedule->command('reports:prune')
    ->dailyAt('02:00')
    ->description('Prune stale report exports')
    ->withoutOverlapping();

Treat manual runs as a smoke-test harness, not production tooling. The Run button executes the event in the current web request. Use it in local/staging to validate arguments and output; for production, keep the actual execution on the cron-driven schedule:run. If you must allow it in prod, wrap long jobs behind a queued command so the web request returns immediately.

Push logic into Artisan commands, not closures. Since the extension can only reason about named commands, any non-trivial ->call(...) should become a proper command class. This also gives you consistent output capture and lets the same command be run via CLI or the UI.

Gate the menu by role. The extension respects laravel-admin's menu/permission system, so the practical pattern is: import the menu, then in Admin → Menu restrict the Scheduling item to a super or ops role. Don't leave it visible to every administrator — it gives arbitrary command execution within the schedule.

Environment-gate the registration. In config/admin.php, conditionally remove the extension or the menu entry outside non-production:

'extensions' => array_filter([
    'scheduling' => env('APP_ENV') !== 'production' ? [] : null,
]),

Or hide the menu item via a Menu:: override in a service provider.

Pair with withoutOverlapping() and onOneServer(). These are still enforced for manual runs (the mutex is checked the same way), which is usually what you want — it prevents you double-firing a job someone else already triggered. Be aware that a manual run will be silently skipped if a cron run is mid-flight.

Capture output deliberately. If a command uses ->appendOutputTo(storage_path('logs/task.log')), the UI may show nothing for that run. For tasks you frequently test from the UI, rely on $this->output / info() in the command so the extension can surface it, or check the log file directly.

Use it as an audit aid. The expression + description table is a quick way to answer "what's actually scheduled in this app?" — including package-registered tasks you forgot about. Sort by next run to spot collisions (three jobs at 02:00 is a smell).

Gotchas and Tips

  • Maintenance risk. Last release was October 2021. It works against the older laravel-admin 1.x line and Laravel 5.5–8 reasonably well; expect friction on Laravel 9+ and PHP 8.1+. If you adopt it, pin the version and plan to fork — the surface area is small (a controller + a Blade view), so a fork is cheap.
  • Closures are second-class. ->call(fn () => ...) tasks appear in the list but often can't be executed from the UI (or execute with no output). If the Run button 500s, this is the first thing to check.
  • Timezone drift. The "next run" column is computed in the app timezone, but the actual schedule:run cron fires on the server's clock. If APP_TIMEZONE and the OS timezone differ, the UI will lie to you. Verify with date on the box.
  • Stuck mutexes after a manual run. If a web request times out mid-task, withoutOverlapping leaves the cache mutex in place and every subsequent run is skipped invisibly. Fix with php artisan schedule:clear-cache (Laravel 8+) or by deleting the cache key.
  • Web request limits. Manual runs inherit max_execution_time, PHP-FPM timeouts, and memory limits. A task that's fine under CLI (php -d memory_limit=-1) can blow up in the browser. Keep manual-testable tasks short, or queue them.
  • The cron line is still mandatory. The extension does not run the scheduler for you. You still need * * * * * cd /path && php artisan schedule:run >> /dev/null 2>&1 in the crontab; the UI is purely observational + manual trigger.
  • Re-importing duplicates the menu. Running php artisan admin:import scheduling twice creates a second menu row. Delete the stale one in Admin → Menu rather than re-importing blindly.
  • CSRF and middleware. The Run action is a POST routed through the admin middleware stack. If you've customized the admin route prefix or added middleware, verify the extension's routes still resolve (php artisan route:list | grep schedul).
  • Extension points are thin. Config is essentially the admin menu entry; if you need per-task enable/disable toggles, custom output viewers, or historical run logs, you're writing them yourself (or switching to a package like spatie/laravel-schedule-monitor for observability). This extension is a viewer, not a scheduler manager — set expectations accordingly.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log