Installation Add the bundle via Composer:
composer require dansan/jobboy-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Dansan\JobBoyBundle\JobBoyBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console config:dump-reference JobBoyBundle
Override in config/packages/jobboy.yaml:
jobboy:
driver: 'redis' # or 'database'
redis:
host: '127.0.0.1'
port: 6379
database:
connection: 'default'
First Use Case
Define a job class (e.g., src/Job/ProcessUserData.php):
namespace App\Job;
use JobBoy\Job;
class ProcessUserData extends Job
{
public function handle()
{
// Your job logic here
return 'Processed!';
}
}
Dispatch the job via a Symfony command or controller:
use JobBoy\JobBoy;
$jobBoy = new JobBoy();
$jobBoy->dispatch(new ProcessUserData());
Job Dispatching
public function createOrder(Request $request)
{
$job = new ProcessOrder($request->input());
$jobBoy->dispatch($job);
return response()->json(['status' => 'queued']);
}
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ProcessBacklogCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$jobBoy->dispatch(new ProcessBacklog());
$output->writeln('Jobs dispatched!');
}
}
Job Chaining
Use JobBoy::chain() to sequence jobs:
$jobBoy->chain([
new ValidateData(),
new TransformData(),
new SaveData(),
]);
Job Retries Configure retries in the job class:
class ProcessUserData extends Job
{
protected $retries = 3;
protected $delay = 60; // seconds
}
Symfony Events
Listen to job events (e.g., JobStarted, JobFailed) via Symfony’s event dispatcher:
# config/services.yaml
services:
App\EventListener\JobListener:
tags:
- { name: 'kernel.event_listener', event: 'jobboy.job.failed', method: 'onJobFailed' }
Doctrine Integration
For database-backed jobs, ensure your Job classes implement Serializable or use Doctrine’s ObjectManager for hydration:
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class ProcessUserData extends Job
{
// ...
}
Testing
Mock JobBoy in tests:
$jobBoy = $this->createMock(JobBoy::class);
$jobBoy->expects($this->once())
->method('dispatch')
->with($this->isInstanceOf(ProcessUserData::class));
Driver-Specific Quirks
timeout in jobboy.redis config or implement reconnection logic.serialize() for complex data or store references.
Fix: Limit job payload size or offload data to a separate table.Job Serialization
Serializable or have a __serialize()/__unserialize() method.
Fix: Use JobBoy\SerializableJob as a base class or manually handle serialization.Symfony Cache Conflicts
$cache->delete('jobboy.*') after processing batches.Race Conditions
pessimistic_write in Doctrine).Log Job Events Enable Symfony’s profiler to inspect job execution:
# config/packages/dev/monolog.yaml
handlers:
jobboy:
type: stream
path: "%kernel.logs_dir%/jobboy.log"
level: debug
Listen for events in JobListener:
public function onJobFailed(JobFailedEvent $event)
{
$this->logger->error('Job failed', [
'job' => $event->getJob(),
'error' => $event->getError(),
]);
}
Check Job Status
Use the JobBoy facade to inspect pending/failed jobs:
$pending = $jobBoy->pending();
$failed = $jobBoy->failed();
Custom Drivers
Extend JobBoy\Driver\DriverInterface to support new backends (e.g., RabbitMQ):
class RabbitMQDriver implements DriverInterface
{
public function push(Job $job) { /* ... */ }
public function pop() { /* ... */ }
}
Register in config/packages/jobboy.yaml:
jobboy:
driver: 'App\JobBoy\RabbitMQDriver'
Middleware Add middleware to jobs (e.g., logging, auth):
$jobBoy->middleware(function (Job $job, callable $next) {
$this->logger->info('Job started', ['job' => get_class($job)]);
return $next($job);
});
Job Metadata Attach metadata to jobs for tracking:
$job = new ProcessUserData();
$job->setMetadata(['user_id' => 123, 'priority' => 'high']);
$jobBoy->dispatch($job);
Retrieve metadata in handlers:
$userId = $this->getMetadata('user_id');
How can I help you explore Laravel packages today?