Search by

t-labs-co / command-scheduler

t-labs-co

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.

Package info

github.com/T-Labs-Co/command-scheduler

pkg:composer/t-labs-co/command-scheduler

Fund package maintenance!

ty-huynh

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-10-25 07:42 UTC

This package is auto-updated.

Last update: 2026-10-27 05:57:36 UTC


README

Tests Static Analysis License: MIT PHP Version Laravel Version

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 or SchedulableCommand interface.
  • 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.0 or ^13.0
  • Livewire ^3.0 or ^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