Queues/Workers
Some tasks, like processing large CSV uploads, can slow down your app and hurt the user experience. Leaf makes it easy to offload heavy work to background jobs, keeping your app fast and responsive. With built-in queuing, you get better performance without the complexity.
Queues are only supported by Leaf MVC. We plan to add support for Leaf Core in the near future.
Leaf queues have three parts: the queue (stores jobs), the job (task to run), and the worker (processes jobs). You push jobs to the queue, and the worker processes them.
Installation
To get started with Queues in Leaf, you need to install the leaf/queue
package:
leaf install queue@v4.0-beta
composer require leafs/queue:v4.0-beta
This will install the Leaf Queue package and set up the necessary files and commands for you to start using queues in your Leaf app.
By default, Leaf MVC uses your database as the queue backend, storing jobs in a leaf_php_jobs
table. If you're fine with these defaults, just restart your server—Leaf will detect the queue setup and automatically start processing jobs alongside the PHP and Vite servers.
Creating a job
Jobs handle background tasks like sending emails after user registration. Instead of delaying the response, you can dispatch a job to the queue, keeping your app fast and responsive.
You can create a new job using the g:job
command:
php leaf g:job SendEmail
This creates a SendEmailJob
class in app/jobs
with a handle()
method that runs when the job is processed. You can add any logic here, like using UserMailer to send an email:
<?php
namespace App\Jobs;
use Leaf\Job;
use App\Mailers\UserMailer;
class SendEmailJob extends Job
{
/**
* Handle the job.
* @return void
*/
public function handle($userId)
{
UserMailer::welcome($userId)->send();
}
}
Dispatching a job
After creating a job, you can dispatch it to the queue using the global dispatch()
function:
dispatch(SendEmailJob::class);
Some jobs like the send email job above may require some data to be passed to the job. You can pass data to the job using the with()
method on the job:
dispatch(SendEmailJob::with($userId));
You can also dispatch multiple jobs at once:
dispatch([
SendEmailJob::with($userId),
SendReminderJob::with($userId),
ScheduleFlightJob::with($userId),
]);
Specifying options for a job
There are times when you need a job to behave a specific way, for instance, you may want to delay a job for a few minutes or specify the number of times a job should be attempted. You can do that by directly setting the options on the job:
<?php
namespace App\Jobs;
use Leaf\Job;
use App\Mailers\UserMailer;
class SendEmailJob extends Job
{
protected $delay = 10; // add 10 sec delay //
protected $tries = 1; // try job only once (default 3) //
/**
* Handle the job.
* @return void
*/
public function handle($userId)
{
UserMailer::welcome($userId)->send();
}
}
The available options are:
Option | Description |
---|---|
delay | The number of seconds to wait before processing a job. |
delayBeforeRetry | The number of seconds to wait before retrying a job that has failed. |
expire | The number of seconds to wait before archiving a job that has not yet been processed. |
force | Whether to force the worker to process the job, even if it has expired or has reached its maximum number of retries. |
memory | The maximum amount of memory the worker may consume. |
timeout | The number of seconds a child process can run before being killed. |
tries | The maximum number of times a job may be attempted. |
Without a worker running, your jobs will just sit in the queue without being processed.
Limitations of Queues/Workers
Just as with every other aspect of Leaf, we try to set everything up for you so you can get started right after running leaf install
. This makes Leaf's queue system very easy to use, but it also comes with some limitations:
- Queues are completely stateless. This means that you can't access the current request, user, session, or any other stateful data in your jobs. If you need to access the current request, you should pass the necessary data to the job as a parameter.
- Due to its simplicity, Leaf's queue system is not as feature-rich as other queue systems like Laravel's. We are working on adding more features to the queue system.
Configuration
If you want to change the default config for the queues and workers, you need to publish the queue config file using the MVC console:
php leaf config:publish queue
This will generate a queue.php
file in your config
directory which looks something like this:
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection
|--------------------------------------------------------------------------
|
| Here you may specify which of the queue connections below you wish
| to use as your default connection for all queue work.
|
*/
'default' => _env('QUEUE_CONNECTION', 'database'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection options for every queue backend
| used by your application. An example configuration is provided for
| each backend supported by Leaf. You're also free to add more.
|
| Drivers: "database", "redis (BETA)", "file (WIP)"
|
*/
'connections' => [
'database' => [
'driver' => 'database',
'connection' => _env('DB_QUEUE_CONNECTION', 'default'),
'table' => _env('DB_QUEUE_TABLE', 'leaf_php_jobs'),
],
'redis' => [
'driver' => 'redis',
'connection' => _env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => _env('REDIS_QUEUE', 'default'),
],
],
];
You can set up multiple queue connections, and Leaf will connect to them when a job is run. For now, only database queues are supported, but we are working on redis and file drivers which will be available pretty soon.
Using a different connection
Once you have configured another database connection, you can run a job using that queue connection by specifying it inside the job you create like this:
<?php
namespace App\Jobs;
use Leaf\Job;
use App\Mailers\UserMailer;
class SendEmailJob extends Job
{
protected $connection = 'myOtherConnection';
/**
* Handle the job.
* @return void
*/
public function handle($userId)
{
UserMailer::welcome($userId)->send();
}
}
From there, you can dispatch the job just as you always do:
dispatch(SendEmailJob::with($userId));
Deployment
Leaf sets up the necessary files and commands for you to start using queues in your Leaf app. However, once deployed, you’ll need to set up your server to keep your workers running continuously. Check out this guide on deploying queues/workers for more information.