Awesome
<p align="center"> <img height="100%" src="assets/cover.png"/> </p> <p align="center"> <a href="https://github.com/a-bashtannik/fasti/actions"><img src="https://github.com/a-bashtannik/fasti/actions/workflows/unit-tests.yml/badge.svg" alt="Build Status"></a> <a href="https://packagist.org/packages/a-bashtannik/fasti"><img src="https://img.shields.io/packagist/dt/a-bashtannik/fasti?style=flat" alt="Total Downloads"></a> <a href="https://packagist.org/packages/a-bashtannik/fasti"><img src="https://img.shields.io/packagist/v/a-bashtannik/fasti?style=flat" alt="Latest Stable Version"></a> <a href="https://packagist.org/packages/a-bashtannik/fasti"><img src="https://img.shields.io/packagist/l/a-bashtannik/fasti?style=flat" alt="License"></a> </p>Fasti is a Laravel package that enables developers to precisely schedule task execution in the future. With Fasti, you can defer the launch of any Job
for any period, specifying the time and date to the minute. At the designated time, Fasti retrieves the required Job from the repository and either executes it synchronously or dispatches it to a queue.
Unlike Laravel's powerful recurring task scheduler, Fasti focuses on scheduling individual tasks for specific times. It's user-friendly, allowing you to easily create, list, or cancel tasks on demand.
$job = new SendGreetingEmail($user);
Fasti::schedule($job, '2024-12-31 23:59:59'); // Schedule a job for New Year's Eve 2024
Installation
[!NOTE] This package requires PHP 8.2+ and Laravel 11+
composer require a-bashtannik/fasti
Publish migration table:
php artisan vendor:publish --provider="Bashtannik\Fasti\Providers\FastiServiceProvider"
⚠️ Add the tick command to your console.php
file:
use Bashtannik\Fasti\Console\Commands\FastiTickCommand;
Schedule::command(FastiTickCommand::class)->everyMinute();
Usage
Schedule your jobs using well-known Laravel patterns and interfaces.
Jobs are eligible for scheduling with Fasti if they implement a handle()
method. At the scheduled time, Fasti executes your job synchronously within the cron job process thread, alongside any other cron jobs you've defined. To leverage Laravel's queuing system, simply implement the ShouldQueue
interface on your job class. This allows Fasti to dispatch the job to Laravel's queue using the standard Bus facade behind the scenes.
use \Bashtannik\Fasti\Facades\Fasti;
class SendGreetingEmail implements ShouldQueue
{
public function handle()
{
// Send the email
}
}
$job = new SendGreetingEmail($user);
Fasti::schedule($job, '2024-12-31 23:59:59'); // Push job to the queue for New Year's Eve 2024
This job will be executed synchronously at the specified time:
use \Bashtannik\Fasti\Facades\Fasti;
class SendAlarmNotification
{
public function handle()
{
// Send the notification
}
}
$job = new SendAlarmNotification();
Fasti::schedule($job, '2025-01-01 08:00:00'); // Execute job synchronously on New Year's Day 2025
Fasti supports encrypted jobs if class implements ShouldEncrypt
interface.
Use tiny Eloquent model to store scheduled tasks
Fasti includes a lightweight Eloquent model that stores essential job information: ID, payload, and dates. While Fasti provides a service for convenient job management, you're not limited to it. In your controllers, you have the flexibility to interact directly with the Eloquent model using standard queries if you need more fine-grained control or custom operations.
// Use the facade
use \Bashtannik\Fasti\Facades\Fasti;
Fasti::all();
Fasti::schedule($job, $at);
Fasti::scheduled($at); // List all jobs scheduled for a specific time
Fasti::cancel($job);
Fasti::cancelled(); // List all cancelled jobs
Fasti::find($id);
// Or use the Eloquent model directly
use \Bashtannik\Fasti\Models\ScheduledJob;
ScheduledJob::where('scheduled_at', '=', '2024-12-31 23:59:59')->get();
Testing
Test your scheduled jobs with ease using Fasti's Fasti::fake()
method and built-in assertions.
use \Bashtannik\Fasti\Facades\Fasti;
// If you are using custom model or repository, avoid using this method and test real storage instead.
Fasti::fake();
// Test if the expected job is scheduled
Fasti::assertScheduled($job);
// Or by job class name
Fasti::assertScheduled(SendGreetingEmail::class);
// Add custom assertion by using callback
Fasti::assertScheduled(function ($job) {
return $job->type === 'send_greeting_email';
});
// Many other assertions are available
Fasti::assertNotScheduled($job);
Fasti::assertScheduledAt($job, '2024-12-31 23:59:59');
Fasti::assertNotScheduledAt($job, '2024-12-31 23:59:59');
Fasti::assertCancelled($job);
Fasti operates as a scheduling layer for your Laravel jobs, focusing solely on when to initiate them. It's important to note that Fasti doesn't manage job execution, queues, releases, attempts, or failures.
Instead, when the scheduled time arrives, Fasti simply hands off the job to Laravel's default Bus
.
It means you are free to use well-known Bus assertion methods shipped with Laravel when the job is dispatched to the queue.
Bus::assertDispatched($job);
Bus::assertNotDispatched($job);
// etc.
Using custom models or storage to manage scheduled jobs
For simple applications, Fasti's built-in Eloquent model is sufficient. However, if you need to store scheduled jobs in a custom database table or use a different storage mechanism, Fasti provides a way to do so.
Define your own model implementing the Bashtannik\Fasti\Contracts\SchedulableJob
interface.
It's important to note that while your model is required to implement this interface, it doesn't overload it with new properties or methods. This approach allows Eloquent to operate normally. You are simply required to provide a standard set of fields in the model or data transfer object to ensure Fasti works smoothly and your IDE's type checking is happy.
use Illuminate\Database\Eloquent\Model;
use Bashtannik\Fasti\Contracts\SchedulableJob;
class MyOwnModel extends Model implements SchedulableJob
{
// Your code
}
Create your own repository that implements the FastiScheduledJobsRepository
interface and bind it in your app service provider register()
method.
use Bashtannik\Fasti\Repositories\FastiRepository;
use App\Repositories\MyOwnRepository;
$this->app->bind(
FastiScheduledJobsRepository::class,
MyOwnRepository::class
);
// Or if you just need to switch the model
$this->app->bind(
FastiScheduledJobsRepository::class,
function () {
$repository = new FastiEloquentRepository;
$respository::$model = MyOwnModel::class;
return $repository;
}
);
Hint: store human-friendly job type name
When using FastiEloquentRepository
repository, by default it stores class name in the type
field.
However, you can define your own set of human-friendly names in your AppServiceProvider like you do with morph-many relationships.
use Bashtannik\Fasti\Repositories\FastiEloquentRepository;
FastiEloquentRepository::enforceTypeMapping([
'fake_job' => FakeJob::class,
]);
This field doesn't affect the job execution but can be useful for debugging or logging purposes.
Hint: monitor your scheduled jobs using artisan fasti:list
command
<img src="https://github.com/user-attachments/assets/c8618517-d80a-4f36-b25b-b2d9f226f4d5" width="50%">
Simulate time in your manual tests and check if the job is executed
php artisan fasti:tick --now="2024-12-31 23:59:59"