Installation:
composer require effiana/job-queue-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Effiana\JobQueueBundle\EffianaJobQueueBundle::class => ['all' => true],
];
Configure the Bundle:
Update config/packages/effiana_job_queue.yaml with your queue driver (e.g., doctrine, database, or redis):
effiana_job_queue:
driver: doctrine
connection: default
table: job_queue
First Use Case: Convert a Symfony command to a background job:
// src/Command/MyCommand.php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Effiana\JobQueueBundle\JobQueue\JobQueueInterface;
class MyCommand extends Command
{
protected static $defaultName = 'app:my-command';
private $jobQueue;
public function __construct(JobQueueInterface $jobQueue)
{
parent::__construct();
$this->jobQueue = $jobQueue;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->jobQueue->addJob(
'app:my-command',
['--option' => 'value'], // Command arguments
'now' // Schedule time (e.g., '+1 hour' for delayed)
);
return Command::SUCCESS;
}
}
Run the Queue Worker:
php bin/console effiana:job-queue:consume
Scheduling Jobs:
$this->jobQueue->addJob('app:command', [], '+10 minutes');
CronExpression:
$this->jobQueue->addJob('app:daily-report', [], '0 0 * * *');
Dependency Injection:
Inject JobQueueInterface into services to queue commands dynamically:
public function __construct(JobQueueInterface $jobQueue) {
$this->jobQueue = $jobQueue;
}
Job Prioritization:
Use the priority option (lower = higher priority):
$this->jobQueue->addJob('app:high-priority', [], 'now', 1);
Handling Output/Errors: Redirect command output to a file or log:
# config/packages/effiana_job_queue.yaml
effiana_job_queue:
log_output: true
log_file: '%kernel.logs_dir%/job_queue.log'
Laravel Compatibility:
If using Laravel, alias the bundle in config/app.php:
'aliases' => [
'JobQueue' => Effiana\JobQueueBundle\JobQueue\JobQueue::class,
],
Then inject JobQueue instead of JobQueueInterface.
Queue Workers in Production: Run workers in a separate process (e.g., Supervisor):
[program:jobqueue]
command=php /path/to/bin/console effiana:job-queue:consume
autostart=true
autorestart=true
user=www-data
numprocs=4
Custom Job Classes:
Extend Effiana\JobQueueBundle\JobQueue\Job for custom logic:
namespace App\JobQueue;
use Effiana\JobQueueBundle\JobQueue\Job;
class CustomJob extends Job
{
public function __construct(string $command, array $arguments = [], string $schedule = 'now', int $priority = 0)
{
parent::__construct($command, $arguments, $schedule, $priority);
$this->setCustomProperty('key', 'value');
}
}
Database Locking:
doctrine driver uses database locks for job processing. Ensure your database supports SELECT ... FOR UPDATE.redis or database driver for high-concurrency environments.Command Arguments:
Worker Stuck on Jobs:
php bin/console effiana:job-queue:release to free stuck jobs.Timezone Issues:
config/packages/framework.yaml:
framework:
timezone: UTC
php bin/console effiana:job-queue:list
tail -f var/log/job_queue.log
php bin/console effiana:job-queue:purge
Driver-Specific Settings:
job_queue table. Run migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
predis/predis is installed:
composer require predis/predis
Environment Variables:
Override settings via .env:
JOB_QUEUE_DRIVER=redis
JOB_QUEUE_REDIS_URL=redis://localhost:6379
Custom Job Storage:
Implement Effiana\JobQueueBundle\JobQueue\JobRepositoryInterface for custom storage (e.g., Elasticsearch).
Event Listeners:
Subscribe to job events (e.g., JobStarted, JobFailed):
// src/EventListener/JobListener.php
namespace App\EventListener;
use Effiana\JobQueueBundle\Event\JobEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class JobListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'job.started' => 'onJobStarted',
'job.failed' => 'onJobFailed',
];
}
public function onJobStarted(JobEvent $event) {
// Log job start
}
public function onJobFailed(JobEvent $event) {
// Handle failures (e.g., send Slack alert)
}
}
Retry Logic:
Configure retries in config/packages/effiana_job_queue.yaml:
effiana_job_queue:
max_retries: 3
retry_delay: 300 # 5 minutes
How can I help you explore Laravel packages today?