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,
];