enqueue/job-queue
Enqueue Job Queue is a transport-agnostic PHP job queue component that adds higher-level features like unique jobs, sub-jobs, dependent jobs, and more. Built on top of Enqueue transports; includes docs, community support, and MIT license.
Installation
composer require enqueue/job-queue
Requires a transport (e.g., Redis, RabbitMQ, Doctrine DBAL). Install one first:
composer require enqueue/redis
Configure Transport
Add to config/queue.php (or create a custom config):
'connections' => [
'enqueue' => [
'driver' => 'enqueue',
'dsn' => 'redis://localhost',
],
],
First Job Define a job class:
use Enqueue\Job\JobInterface;
use Enqueue\Job\Job;
class SendEmailJob implements JobInterface
{
public function __construct(private string $email) {}
public function run(): void
{
// Logic to send email
}
public static function create(): JobInterface
{
return new self('user@example.com');
}
}
Dispatch a Job
use Enqueue\Client\Producer;
$producer = new Producer(new \Enqueue\Redis\RedisConnection('redis://localhost'));
$producer->send(new SendEmailJob('user@example.com'));
Consume Jobs
php artisan queue:work --queue=enqueue
Or programmatically:
use Enqueue\Client\Consumer;
$consumer = new Consumer(new \Enqueue\Redis\RedisConnection('redis://localhost'));
$consumer->consume(function (JobInterface $job) {
$job->run();
return true; // Acknowledge job completion
});
Chain jobs with Job::createSubJob() or Job::createDependentJob():
$parentJob = new ParentJob();
$subJob = Job::createSubJob(new ChildJob(), $parentJob);
$producer->send($subJob);
Prevent duplicate execution with Job::createUniqueJob():
$uniqueJob = Job::createUniqueJob(
new SendEmailJob('user@example.com'),
'send_email_unique_key',
3600 // TTL in seconds
);
$producer->send($uniqueJob);
Schedule jobs for later:
$delayedJob = Job::createDelayedJob(new SendEmailJob('user@example.com'), new \DateTime('+1 hour'));
$producer->send($delayedJob);
Implement retry logic in the job:
class RetryableJob implements JobInterface
{
public function run(): void
{
try {
// Risky operation
} catch (Exception $e) {
throw new Job\RetryableException($e->getMessage(), 3); // Retry 3 times
}
}
}
Use the enqueue/laravel bridge for seamless Laravel integration:
composer require enqueue/laravel
Publish config:
php artisan vendor:publish --provider="Enqueue\Laravel\LaravelServiceProvider"
Dispatch jobs like Laravel’s native queue:
dispatch(new SendEmailJob('user@example.com'));
Illuminate\Queue\QueueManager with Enqueue\Laravel\QueueManager.dispatch() helper or Bus facade for job dispatching.App\Providers\QueueServiceProvider to use Enqueue’s connection.Enqueue\Symfony\MessageBusFactory to integrate with Symfony Messenger.config/packages/enqueue.yaml.Enqueue\Client\Inspection\InspectionClient to inspect jobs:
$inspector = new InspectionClient(new \Enqueue\Redis\RedisConnection('redis://localhost'));
$jobs = $inspector->getJobs();
$producer->sendBatch([
new SendEmailJob('user1@example.com'),
new SendEmailJob('user2@example.com'),
]);
Transport Compatibility
$connection = new \Enqueue\Redis\RedisConnection('redis://localhost');
if (!$connection->isConnected()) {
throw new \RuntimeException('Transport not connected');
}
Job Serialization
__serialize() and __unserialize() for custom serialization:
public function __serialize(): array
{
return ['email' => $this->email];
}
public function __unserialize(array $data): void
{
$this->email = $data['email'];
}
Acknowledgment
true from the consumer callback to acknowledge job completion. Returning false or throwing an exception will retry the job (if configured).Unique Job Keys
'send_email'), collisions may occur. Use specific keys like 'send_email_user@example.com'.Delayed Jobs
delay plugin or RabbitMQ with x-delay header).Log Consumer Errors Wrap consumer logic in a try-catch:
$consumer->consume(function (JobInterface $job) {
try {
$job->run();
return true;
} catch (Exception $e) {
\Log::error('Job failed', ['job' => get_class($job), 'error' => $e->getMessage()]);
return false; // Retry or dead-letter
}
});
Inspect Jobs
Use the InspectionClient to debug stuck jobs:
$inspector = new InspectionClient($connection);
$jobs = $inspector->getJobs();
foreach ($jobs as $job) {
\Log::info('Pending job', ['job' => $job->getJobName()]);
}
Transport-Specific Issues
enqueue/redis package is installed and Redis is running.enqueue/doctrine).Use Interfaces
Extend JobInterface for all jobs to ensure consistency:
class MyJob implements JobInterface { ... }
Leverage Middleware Add middleware for logging, metrics, or retries:
$producer->setMiddleware([new \Enqueue\Middleware\LoggingMiddleware()]);
Dead-Letter Queues Configure dead-letter queues for failed jobs:
$consumer->setMiddleware([
new \Enqueue\Middleware\DeadLetterMiddleware('dead_letter_queue'),
]);
Testing
Use Enqueue\Test\JobTestCase for unit tests:
use Enqueue\Test\JobTestCase;
class SendEmailJobTest extends JobTestCase
{
public function testJobExecution()
{
$job = new SendEmailJob('user@example.com');
$this->assertTrue($job->run());
}
}
Custom Transports
Extend Enqueue\Transport\TransportInterface for custom transports (e.g., Kafka, NATS).
Environment-Specific Config
Use Laravel’s .env or Symfony’s parameters.yaml to switch transports between environments:
QUEUE_CONNECTION=enqueue
ENQUEUE_DSN=redis://localhost:6379
Job Priorities Use transport-specific features (e.g., RabbitMQ priorities) for job prioritization:
$producer->send(new HighPriorityJob(), ['priority' => 1]);
How can I help you explore Laravel packages today?