You can run queue jobs in your application right after the installation of the application server. Web and GRPC bundles
come with pre-configured queue service capable of running your tasks using an ephemeral broker.
To run a job, you must create a proper job handler. The handler must implement Spiral\Queue\HandlerInterface. Handlers
are responsible for job payload serialization and execution. Use Spiral\Queue\JobHandler to simplify your abstraction
and perform dependency injection in your handler method invoke:
namespace App\Jobs;
use Spiral\Queue\JobHandler;
class SampleJob extends JobHandler
{
public function invoke(): void
{
// do something
}
}
You can freely use method injection in your handler:
namespace App\Jobs;
use Spiral\Queue\JobHandler;
class SampleJob extends JobHandler
{
public function invoke(MyService $service): void
{
// Do something with service
}
}
Note
You can define handlers as singletons for higher performance.
You can dispatch your job via Spiral\Queue\QueueInterface or via prototype property queue. The method push of
QueueInterface accepts job name, the payload in array form, and additional options.
use App\Jobs\SampleJob;
use Spiral\Queue\QueueInterface;
public function createJob(QueueInterface $queue): void
{
$queue->push(SampleJob::class);
}
You can use your handler name as a job name. It will be automatically converted into - identifier, for example,
App\Jobs\SampleJob will be presented as app-jobs-sampleJob.
Job handlers can accept any number of job parameters via the second argument of QueueInterface->push(). Parameters
provided in array form. No objects are supported (see below how to bypass it) to ensure compatibility with consumers
written on other languages.
use App\Jobs\SampleJob;
use Spiral\Queue\QueueInterface;
public function createJob(QueueInterface $queue): void
{
$queue->push(SampleJob::class, ['value' => 123]);
}
You can receive passed payload in handler using the parameter payload of invoke method:
use Spiral\Queue\JobHandler;
class SampleJob extends JobHandler
{
public function invoke(array $payload): void
{
dump($payload);
}
}
In addition to that, the default Spiral\Queue\JobHandler implementation will pass all values of the payload as method
arguments:
use Spiral\Queue\JobHandler;
class SampleJob extends JobHandler
{
public function invoke(string $value): void
{
dump($value);
}
}
If you don't want to use job handler class name as a queue job name like in an example below:
use Spiral\Queue\QueueInterface;
public function createJob(QueueInterface $queue): void
{
$queue->push('sample::job');
}
you need to tell a queue how to handle a job with name sample::job.
You can do it via app/config/queue.php config:
<?php
declare(strict_types=1);
return [
'registry' => [
'handlers' => [
'sample::job' => App\Jobs\SampleJob::class
],
],
];
or via Spiral\Queue\QueueRegistry:
use Spiral\Boot\Bootloader\Bootloader;
class MyBootloader extends Bootloader
{
public function boot(\Spiral\Queue\QueueRegistry $registry): void
{
$registry->setHandler('sample::job', \App\Jobs\SampleJob::class);
}
}
When a job pushed into a queue, a job payload would be serialized via Spiral\Queue\SerializerInterface.
Note
By default, the payload will be serialized with default serializerSpiral\Queue\DefaultSerializer->opis/closure.
By default, all failed jobs will be sent into spiral log. But you can change default behavior. At first, you need to
create your own implementation for Spiral\Queue\Failed\FailedJobHandlerInterface.
use Spiral\Queue\Failed\FailedJobHandlerInterface;
use Cycle\Database\DatabaseInterface;
use Spiral\Queue\SerializerInterface;
class DatabaseFailedJobsHandler implements FailedJobHandlerInterface
{
private DatabaseInterface $database;
private SerializerInterface $serializer;
public function __construct(DatabaseInterface $database, SerializerInterface $serializer)
{
$this->database = $database;
$this->serializer = $serializer;
}
public function handle(string $driver, string $queue, string $job, array $payload, \Throwable $e): void
{
$this->database
->insert('failed_jobs')
->values([
'driver' => $driver,
'queue' => $queue,
'job_name' => $job,
'payload' => $this->serializer->serialize($payload),
'error' => $e->getMessage(),
])
->run();
}
}
Then you need to bind your implementation with Spiral\Queue\Failed\FailedJobHandlerInterface interface.
namespace App\Bootloader;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\RoadRunnerBridge\Queue\Failed\FailedJobHandlerInterface;
final class QueueFailedJobsBootloader extends Bootloader
{
protected const SINGLETONS = [
FailedJobHandlerInterface::class => \App\Jobs\DatabaseFailedJobsHandler::class,
];
}
And register this bootloader after QueueFailedJobsBootloader in your application
protected const APP = [
// ...
App\Bootloader\QueueFailedJobsBootloader::class,
];