neelkanthk/laravel-schedulable
Installation:
composer require neelkanthk/laravel-schedulable
Publish the migration (if using custom column names):
php artisan vendor:publish --provider="Neelkanth\LaravelSchedulable\LaravelSchedulableServiceProvider" --tag="migrations"
php artisan migrate
Apply the Trait:
Add Schedulable trait to your Eloquent model:
use Neelkanth\LaravelSchedulable\Schedulable;
class Task extends Model
{
use Schedulable;
}
First Use Case: Schedule a model for a future time:
$task = Task::create(['name' => 'Quarterly Report']);
$task->scheduleAt(Carbon::now()->addDays(30)); // Schedule for 30 days later
Scheduling Models:
// Schedule for a specific Carbon instance
$model->scheduleAt(Carbon::now()->addHours(2));
// Schedule for a relative time (uses Carbon's syntax)
$model->scheduleAt('+1 week');
Querying Scheduled Models:
// Get all scheduled models (active or future)
$scheduledModels = Task::scheduled()->get();
// Get only active scheduled models (not yet executed)
$activeModels = Task::scheduled()->active()->get();
// Get models scheduled for a specific time
$modelsAtTime = Task::scheduled()->at(Carbon::now())->get();
Rescheduling/Unscheduling:
// Reschedule to a new time
$model->rescheduleAt(Carbon::now()->addDays(7));
// Unschedule (sets scheduled_at to null)
$model->unschedule();
Lifecycle Hooks: Override default events in your model:
protected static function scheduled($model)
{
// Runs when a model is scheduled
Log::info("Model {$model->id} scheduled for {$model->scheduled_at}");
}
protected static function unscheduled($model)
{
// Runs when a model is unscheduled
}
protected static function executed($model)
{
// Runs when a model's scheduled time is reached
}
executed() fires:
protected static function executed($model)
{
dispatch(new ProcessTaskJob($model));
}
SoftDeletes trait.public function scopeUpcoming($query)
{
return $query->scheduled()->where('scheduled_at', '>', now());
}
Timezone Handling:
Ensure scheduled_at uses the correct timezone (default: app timezone). Explicitly set timezone when scheduling:
$model->scheduleAt(Carbon::now()->setTimezone('UTC')->addHours(2));
Database Indexing:
The scheduled_at column should be indexed for performance:
Schema::table('tasks', function (Blueprint $table) {
$table->dateTime('scheduled_at')->nullable()->index();
});
Race Conditions:
The executed() event fires when the query fetches models with scheduled_at <= now(). In high-traffic apps, consider:
Laravel\Queue\InteractsWithQueue) in executed().Custom Column Names:
If overriding the default scheduled_at column, ensure the trait’s config is updated:
'column' => 'custom_schedule_time',
in config/laravel-schedulable.php.
Task::scheduled()->dd(); // Debug all scheduled models
protected static function scheduled($model)).Custom Logic on Execution:
Extend the executed() method to trigger additional actions:
protected static function executed($model)
{
if ($model->isHighPriority()) {
notifyAdmins($model);
}
}
Batch Processing: Create a command to process all overdue models:
php artisan schedule:process --overdue
(Requires custom implementation; the package doesn’t include this out-of-the-box.)
Soft Unscheduling:
Modify the unschedule() method to mark models as "completed" instead of nulling scheduled_at:
public function unschedule()
{
$this->update(['scheduled_at' => null, 'status' => 'completed']);
}
How can I help you explore Laravel packages today?