t-labs-co / command-scheduler
Code-first command scheduling framework for Laravel — discover schedulable commands via PHP 8 attributes or interfaces, persist schedule definitions to database, enforce run windows, and control tasks via Livewire dashboard or CLI.
Fund package maintenance!
Requires
- php: ^8.4
- dragonmantank/cron-expression: ^3.6
- illuminate/console: ^12|^13
- illuminate/database: ^12|^13
- illuminate/events: ^12|^13
- illuminate/filesystem: ^12|^13
- illuminate/routing: ^12|^13
- illuminate/support: ^12|^13
- livewire/livewire: ^3|^4
- lorisleiva/cron-translator: ^0.5
- robsontenorio/mary: ^2.1
Requires (Dev)
- larastan/larastan: ^3
- laravel/pint: ^1
- orchestra/testbench: ^10|^11
- pestphp/pest: ^4|^5
- pestphp/pest-plugin-laravel: ^4|^5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Code-first command scheduling framework for Laravel — discover schedulable commands via PHP 8 attributes or interfaces, persist schedule definitions to database, enforce run windows, and control tasks via a Livewire/MaryUI dashboard or CLI.
Features
- Code-First Scheduling: Define schedules right on Artisan command classes using
#[Scheduled]PHP 8 attributes orSchedulableCommandinterface. - Run Windows: Restrict command execution to specific business windows (
WORKING_HOURS,WEEKEND,HOLIDAY,TRADING,PREMARKET, etc.) without writing complex cron expressions. - Database Runtime Controls: Sync discovered tasks to database (
cs_scheduled_tasks), allowing administrators to toggle tasks or adjust parameters at runtime without redeploying. - Execution Tracking: Automatically log start time, completion time, duration, peak memory usage, and exit codes to
cs_scheduled_command_runs. - Livewire & MaryUI Dashboard: Built-in dashboard to monitor upcoming runs, inspect recent execution logs, toggle tasks, and trigger manual runs.
- Artisan Management: CLI commands for syncing (
scheduler:sync), listing (scheduler:list), running (scheduler:run), and pruning logs (scheduler:prune-logs).
Why not routes/console.php?
Laravel's built-in scheduler is solid, and for a handful of static tasks it's all you need. This package is for when schedules become something you manage, not just something you declare.
| routes/console.php (native) | Command Scheduler | |
|---|---|---|
| Define recurring tasks | ✅ Schedule::command() | ✅ #[Scheduled] attribute |
| Where the schedule lives | Central file, separate from the command | On the command class itself |
| Frequency, windows, timezone, hooks | ✅ Fluent methods | ✅ Cron plus 14 built-in run windows |
| Overlap and single-server locks | ✅ withoutOverlapping(), onOneServer() | Native locks still apply |
| Enable or disable at runtime | Needs a code change and deploy, or custom flags | ✅ Database toggle, no deploy |
| Run history | Not stored by default | ✅ cs_scheduled_command_runs |
| Web UI | None built in | ✅ Optional Livewire dashboard |
| Extra dependencies | None | Package, plus Livewire and MaryUI for the dashboard |
Choose native if your tasks are few and rarely change. Choose this package if you want schedules defined with the command, controlled at runtime, and tracked with run history.
Documentation
- Usage Guide & Examples — All patterns for defining scheduled commands, run windows, composable attributes, events, failure notifications, and migration from native Laravel scheduler.
- Dashboard Setup Guide — Step-by-step guide for installing, configuring, and customizing the Livewire/MaryUI dashboard, including Vite asset building and layout options.
Requirements
- PHP
^8.4 - Laravel
^12.0or^13.0 - Livewire
^3.0or^4.0(for dashboard) - MaryUI
^2.1(for dashboard)
Installation
You can install the package via Composer:
composer require t-labs-co/command-scheduler
Publish and run the migrations:
php artisan migrate
Publish the configuration file (optional):
php artisan vendor:publish --tag="command-scheduler-config"
Defining Scheduled Commands
1. Attribute-Based Scheduling (Recommended)
Add the #[Scheduled] attribute to any Artisan command:
namespace App\Console\Commands; use Illuminate\Console\Command; use TLabsCo\CommandScheduler\Attributes\Scheduled; use TLabsCo\CommandScheduler\Core\Scheduling\Domain\Enums\RunWindow; #[Scheduled( cron: '*/15 * * * *', window: RunWindow::WORKING_HOURS, category: 'maintenance', priority: 10, description: 'Clean up temporary files during working hours' )] class PruneTempFilesCommand extends Command { protected $signature = 'app:prune-temp'; protected $description = 'Clean up temporary files'; public function handle(): int { // ... return self::SUCCESS; } }
2. Interface-Based Scheduling
Implement SchedulableCommand and use IsSchedulable:
namespace App\Console\Commands; use Illuminate\Console\Command; use TLabsCo\CommandScheduler\Contracts\SchedulableCommand; use TLabsCo\CommandScheduler\Core\Scheduling\Domain\Enums\RunWindow; use TLabsCo\CommandScheduler\Core\Scheduling\Domain\ValueObjects\ScheduleDefinition; use TLabsCo\CommandScheduler\Traits\IsSchedulable; class GenerateDailyReportCommand extends Command implements SchedulableCommand { use IsSchedulable; protected $signature = 'report:daily'; public function schedule(): ScheduleDefinition { return ScheduleDefinition::create() ->cron('0 8 * * 1-5') ->window(RunWindow::WORKING_HOURS) ->category('reports') ->priority(20); } public function handle(): int { // ... return self::SUCCESS; } }
Run Windows
Run windows restrict execution to specific time periods regardless of cron schedule. For a complete reference of all 14 run window types, see the Usage Guide.
| Window | Description |
|---|---|
RunWindow::ALWAYS |
No run window constraint (default) |
RunWindow::WORKING_HOURS |
Runs only during configured business working hours |
RunWindow::BEFORE_WORKING_HOURS |
Runs only before business start time |
RunWindow::AFTER_WORKING_HOURS |
Runs only after business end time |
RunWindow::WORKING_DAYS |
Runs on configured working days (e.g. Mon–Fri) |
RunWindow::REST_TIME |
Runs during configured lunch / rest interval |
RunWindow::WEEKEND |
Runs on Saturdays and Sundays |
RunWindow::HOLIDAY |
Runs on configured holiday dates |
RunWindow::TRADING |
Stock market trading hours |
RunWindow::PREMARKET |
Stock market pre-market hours |
RunWindow::AFTERHOURS |
Stock market after-hours |
Artisan Commands
Sync Discovered Commands
Scan command directories and sync definitions to the database:
php artisan scheduler:sync
List Scheduled Tasks
Display all discovered tasks and their database runtime status:
php artisan scheduler:list
Run a Task Manually
Trigger execution immediately, bypassing run window checks if desired:
php artisan scheduler:run app:prune-temp --force
Prune Old Run Logs
Delete execution history older than configured retention days:
php artisan scheduler:prune-logs --days=30
Dashboard Setup
For a complete step-by-step dashboard setup guide — including dependency installation, Vite asset building, layout customization, and troubleshooting — see the Dashboard Setup Guide.
The dashboard is accessible by default at /admin/scheduler (and /scheduler).
Quick Start — Authorization Gate
In your AppServiceProvider or AuthServiceProvider, define the permission gate:
use Illuminate\Support\Facades\Gate; public function boot(): void { Gate::define('viewSchedulerDashboard', function ($user) { return $user->hasRole('admin'); }); }
Testing
Run the test suite using Pest:
composer test
Run static analysis:
composer analyse
License
The MIT License (MIT). Please see License File for more information.
Quality & Development Practices
This package is developed following Laravel best practices, with a strong focus on reliability, maintainability, and code quality.
- 🧩 Laravel Best Practices: Follows established Laravel conventions and recommended design principles.
- ✅ Comprehensive Test Coverage: Features are covered by unit and integration tests using Pest PHP.
- 🔍 Static Analysis: Validated with PHPStan Level 8 using Larastan to catch potential type errors and enforce strict typing.
- 🤖 AI-Assisted Development: AI assistants support development, analysis, and code quality improvements.
- 👨💻 Senior Engineer Review: All changes are carefully reviewed by a senior engineer before each release.
Credits
- Ty Huynh (@ty-huynh) — tyhuynh.id.vn
15+ years · Senior Software Engineer (PHP/Laravel) & Technical Lead