Installation
composer require druidvav/evil-queue-bundle
Add to config/bundles.php:
return [
// ...
Druidvav\EvilQueueBundle\DruidvavEvilQueueBundle::class => ['all' => true],
];
Configure config/packages/dv_evil_queue.yaml
dv_evil_queue:
debug: '%kernel.debug%'
connection: '@doctrine.dbal.xmlrpc_connection' # Replace with your DBAL connection
logger: '@monolog.logger.evil' # Custom logger (optional)
workers: 10 # Default worker count
priority_workers: 5 # Workers for high-priority jobs
First Use Case Create a job class:
namespace App\Jobs;
use Druidvav\EvilQueueBundle\Job\JobInterface;
class SendEmailJob implements JobInterface
{
public function run(): void
{
// Job logic here
}
}
Dispatch it in a controller/service:
use Druidvav\EvilQueueBundle\Dispatcher\JobDispatcherInterface;
class EmailController
{
public function __construct(private JobDispatcherInterface $dispatcher) {}
public function sendWelcomeEmail(): void
{
$this->dispatcher->dispatch(new SendEmailJob());
}
}
Supervisor Setup
Copy the template from docs/ to /etc/supervisor/conf.d/evil-queue.conf and adjust:
[program:evil-queue]
command=php /path/to/bin/console evil-queue:worker
numprocs=10
Start Workers
supervisorctl reread
supervisorctl update
supervisorctl start evil-queue:*
Job Design
JobInterface for all jobs.class ProcessOrderJob implements JobInterface
{
public function __construct(
private OrderRepository $orderRepo,
private EmailService $emailService
) {}
public function run(): void
{
$order = $this->orderRepo->find($this->orderId);
$this->emailService->sendConfirmation($order);
}
}
Dispatching Jobs
$dispatcher->dispatch(new SendEmailJob());
$dispatcher->dispatch(new SendEmailJob(), 3600); // Delay in seconds
$dispatcher->dispatch(new CriticalJob(), 0, true); // High priority
Worker Management
workers and priority_workers in config for load balancing.evil-queue:stop-workers command to halt workers cleanly.monolog.logger.evil or Supervisor status:
supervisorctl status
Integration with Symfony Events
JobStarted, JobFailed) for logging/auditing:
// config/services.yaml
App\EventListener\JobListener:
tags:
- { name: kernel.event_listener, event: evil_queue.job_started, method: onJobStarted }
Database Schema
evil_queue_jobs with columns:
id, payload, status, priority, created_at, processed_at.docs/.Job Chaining Dispatch jobs sequentially in a worker:
class ProcessOrderJob implements JobInterface
{
public function run(): void
{
$this->dispatcher->dispatch(new SendEmailJob());
$this->dispatcher->dispatch(new UpdateInventoryJob());
}
}
Note: Ensure the dispatcher is injected into the job.
Retry Logic
Implement JobInterface::retry() for failed jobs:
public function retry(): void
{
// Custom retry logic (e.g., exponential backoff)
}
Bulk Processing Dispatch multiple jobs in a loop:
foreach ($users as $user) {
$this->dispatcher->dispatch(new SendNewsletterJob($user->id));
}
Dynamic Worker Configuration Override worker count per environment:
# config/packages/dev/dv_evil_queue.yaml
dv_evil_queue:
workers: 5 # Lower in dev
Supervisor Misconfiguration
command points to the correct bin/console path and numprocs matches workers in config.tail -f /var/log/supervisor/evil-queue-stderr.log
Database Locking
evil_queue_jobs.priority_workers for critical jobs and monitor lock contention.Job Serialization
$job = new SendEmailJob();
$job->setPayload(['user_id' => $user->id]); // Store only serializable data
Debugging
dv_evil_queue:
debug: true
monolog.logger.evil to debug for verbose logs.php bin/console evil-queue:listphp bin/console evil-queue:delete-failedWorker Stuck in "Busy" State
JobInterface::run() with proper error handling and timeouts.Environment-Specific Configs
Override settings per environment (e.g., workers: 20 in production, 5 in staging).
Health Checks Add a route to check worker status:
// src/Controller/QueueController.php
public function healthCheck(JobDispatcherInterface $dispatcher): JsonResponse
{
return new JsonResponse([
'workers' => $dispatcher->getWorkerCount(),
'queue_size' => $dispatcher->getQueueSize(),
]);
}
Testing
$dispatcher = $this->createMock(JobDispatcherInterface::class);
$dispatcher->expects($this->once())->method('dispatch');
$this->controller->setDispatcher($dispatcher);
evil-queue:test-worker for isolated job testing.Performance Tuning
doctrine.dbal.xmlrpc_connection is optimized for high concurrency.Extending the Bundle
JobStorageInterface for alternative backends (e.g., Redis).JobEvent classes to add custom events (e.g., JobPaused).Security
public function run(): void
{
if (!is_numeric($this->payload['user_id'])) {
throw new \RuntimeException('Invalid user ID');
}
}
How can I help you explore Laravel packages today?