jiordiviera/laravel-smart-scheduler

A Laravel package for smart task scheduling

Installs: 18

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/jiordiviera/laravel-smart-scheduler

v1.1.0 2025-12-08 12:08 UTC

This package is auto-updated.

Last update: 2025-12-08 12:26:36 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads License

A Laravel package for intelligent scheduled task management with observability, reliability features, and automatic stuck task detection.

Features

  • Task Execution Tracking: Record every scheduled task execution with status, duration, and output
  • Overlap Prevention: Automatically prevent concurrent executions of the same task
  • Stuck Task Detection: Automatically detect and handle tasks that are stuck (server crash, process killed)
  • Failure Notifications: Email notifications for failed and stuck tasks (extensible to other channels)
  • Task History: Maintain execution history with server information
  • Purge Command: Clean up old execution records

Requirements

  • PHP 8.2+
  • Laravel 11.x or 12.x

Installation

Install via Composer:

composer require jiordiviera/laravel-smart-scheduler

Publish the configuration and migrations:

php artisan vendor:publish --tag=smart-scheduler-config
php artisan vendor:publish --tag=smart-scheduler-migrations

Run migrations:

php artisan migrate

Configuration

The package automatically registers a service provider. Configure settings in config/smart-scheduler.php:

return [
    // Days to retain execution records
    'purge_days' => 7,

    // Minutes before a task is considered stuck
    'stuck_timeout_minutes' => 60,

    'notifications' => [
        'email' => [
            'recipients' => ['admin@example.com'],
        ],
        'notify_on_stuck' => true,
    ],
];

Or use environment variables:

SMART_SCHEDULER_PURGE_DAYS=7
SMART_SCHEDULER_STUCK_TIMEOUT=60
SMART_SCHEDULER_EMAIL_RECIPIENTS=admin@example.com,ops@example.com
SMART_SCHEDULER_NOTIFY_STUCK=true

Usage

The package automatically tracks all scheduled tasks defined in routes/console.php:

use Illuminate\Support\Facades\Schedule;

Schedule::command('backup:run')->daily();
Schedule::command('reports:generate')->hourly();

Viewing Execution History

Query the smart_schedule_runs table:

use Jiordiviera\SmartScheduler\LaravelSmartScheduler\Models\ScheduleRun;

// Get recent executions
$runs = ScheduleRun::latest('started_at')->limit(10)->get();

// Get failed executions
$failed = ScheduleRun::where('status', ScheduleRun::STATUS_FAILED)->get();

// Get stuck executions
$stuck = ScheduleRun::where('status', ScheduleRun::STATUS_STUCK)->get();

Purging Old Records

Remove old successful and ignored records:

# Purge records older than configured days
php artisan smart-scheduler:purge

# Purge with custom retention period
php artisan smart-scheduler:purge --days=30

# Dry run to preview what would be deleted
php artisan smart-scheduler:purge --dry-run

Detecting Stuck Tasks

Manually detect and mark stuck tasks:

# Detect stuck tasks (default: 60 minutes timeout)
php artisan smart-scheduler:detect-stuck

# Custom timeout
php artisan smart-scheduler:detect-stuck --timeout=30

# Dry run (preview only)
php artisan smart-scheduler:detect-stuck --dry-run

# Without sending notifications
php artisan smart-scheduler:detect-stuck --no-notify

Note: Stuck tasks are also automatically detected when a new execution of the same task starts.

Recommended Scheduler Setup

Add these commands to your routes/console.php for automatic maintenance:

use Illuminate\Support\Facades\Schedule;

// Purge old records weekly
Schedule::command('smart-scheduler:purge')->weekly();

// Detect stuck tasks every 30 minutes
Schedule::command('smart-scheduler:detect-stuck')->everyThirtyMinutes();

How It Works

The package uses Laravel's event system to intercept scheduled task lifecycle:

┌─────────────────────────────────────────────────────────────────┐
│                    Task Execution Flow                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ScheduledTaskStarting                                          │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐     ┌──────────────┐                         │
│  │ Check stuck  │────▶│ Mark as stuck│ (if > timeout)          │
│  │ tasks        │     │ + notify     │                         │
│  └──────────────┘     └──────────────┘                         │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐     ┌──────────────┐                         │
│  │ Check overlap│────▶│ STATUS_IGNORED│ (if running)           │
│  └──────────────┘     └──────────────┘                         │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐                                              │
│  │STATUS_STARTING│                                              │
│  └──────────────┘                                              │
│         │                                                       │
│         ▼                                                       │
│  ScheduledTaskFinished                                          │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐     ┌──────────────┐                         │
│  │ Exit code = 0│────▶│STATUS_SUCCESS │                         │
│  └──────────────┘     └──────────────┘                         │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐     ┌──────────────┐                         │
│  │ Exit code ≠ 0│────▶│STATUS_FAILED  │ + notify               │
│  └──────────────┘     └──────────────┘                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Task Statuses

Status Description
starting Task is currently running
success Task completed successfully (exit code 0)
failed Task failed (exit code ≠ 0)
ignored Task skipped due to overlap
stuck Task was running too long and marked as stuck

Extending Notifications

Implement SmartNotifierInterface to add custom notification channels:

use Jiordiviera\SmartScheduler\LaravelSmartScheduler\Contracts\SmartNotifierInterface;
use Jiordiviera\SmartScheduler\LaravelSmartScheduler\Models\ScheduleRun;

class SlackNotifier implements SmartNotifierInterface
{
    public function sendFailureNotification(ScheduleRun $run): void
    {
        // Send to Slack
    }

    public function sendStuckNotification(ScheduleRun $run): void
    {
        // Send to Slack
    }
}

Register in a service provider:

$this->app->singleton(SmartNotifierInterface::class, SlackNotifier::class);

Testing

composer test

Code Style

# Check
composer pint

# Fix
composer pint:fix

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

The MIT License (MIT). Please see License File for more information.

Credits