Installation
composer require alexlcdee/symfony-worker
(Note: Requires Symfony Console and FrameworkBundle, so ensure compatibility with Laravel’s Symfony components.)
Basic Worker Command
Create a custom command extending SymfonyWorkerCommand:
// app/Console/Commands/ProcessWorker.php
namespace App\Console\Commands;
use Alexlcdee\SymfonyWorker\SymfonyWorkerCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ProcessWorker extends SymfonyWorkerCommand
{
protected function configure()
{
$this->setName('worker:process')
->setDescription('Process background jobs');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->run(function () {
// Your job logic here (e.g., queue processing)
$output->writeln('Processing job...');
});
}
}
Register Command
Add to app/Console/Kernel.php:
protected $commands = [
\App\Console\Commands\ProcessWorker::class,
];
Run the Worker
php artisan worker:process
(Use --daemon flag for background execution: php artisan worker:process --daemon)
Replace Laravel’s default queue worker with this package for Symfony-style workers:
// app/Console/Commands/QueueWorker.php
use Illuminate\Queue\Worker;
use Symfony\Component\Process\Process;
class QueueWorker extends SymfonyWorkerCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$this = new Worker($this->app->queue(), $this->app->make('events'));
$this->run(function () use ($worker) {
$worker->daemon('default', function () {
$worker->run();
});
});
}
}
--daemon to run workers in the background (requires pcntl extension).
php artisan worker:process --daemon --pid=/tmp/worker.pid
SIGTERM/SIGINT via Symfony’s Process signals:
$this->run(function () {
pcntl_signal(SIGTERM, function () {
$this->getOutput()->writeln('Shutting down...');
exit(0);
});
});
$this->run(function () {
while ($job = $this->app->queue()->getNextJob()) {
$job->payload();
$this->getOutput()->writeln('Processed job: ' . $job->resolveName());
}
});
$this->run(function () {
$jobs = $this->app->queue()->getJobs(['default']);
foreach ($jobs as $job) {
$job->fire();
}
});
$this->run(function () {
$logger = $this->getApplication()->getLogger();
$logger->info('Worker started');
});
getOutput() to use Laravel’s log channel:
protected function getOutput()
{
return new SymfonyOutput($this->app->make('log')->channel('worker'));
}
Process to spawn multiple workers:
$this->run(function () {
$processes = [];
for ($i = 0; $i < 4; $i++) {
$process = new Process(['php', 'artisan', 'worker:process']);
$process->start();
$processes[] = $process;
}
foreach ($processes as $p) $p->wait();
});
Symfony Dependency Conflicts:
5.0 components, which may conflict with Laravel’s Symfony versions.symfony/console and symfony/framework-bundle explicitly in composer.json:
"extra": {
"laravel": {
"dont-discover": ["symfony-worker"]
}
}
Daemon Mode Requires pcntl:
--daemon flag fails without the pcntl extension.php-pcntl or use supervisor for process management.No Built-in Retry Logic:
$attempts = 0;
$this->run(function () use (&$attempts) {
try {
$job->fire();
$attempts = 0;
} catch (\Exception $e) {
if ($attempts++ < 3) sleep(1);
else throw $e;
}
});
Signal Handling Quirks:
Process signals may not propagate correctly in Laravel’s context.pcntl directly for reliability:
pcntl_signal(SIGTERM, function () {
$this->getOutput()->writeln('Terminating...');
exit(128 + SIGTERM);
});
--daemon, verify the PID file:
cat /tmp/worker.pid
kill $(cat /tmp/worker.pid)
console.terminate for cleanup:
$this->getApplication()->getDispatcher()->addListener('console.terminate', function () {
$this->getOutput()->writeln('Cleanup tasks...');
});
Custom Worker Classes:
Extend SymfonyWorkerCommand to add domain-specific logic:
class EmailWorker extends SymfonyWorkerCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->run(function () {
Mail::queue(...);
});
}
}
Hooks for Pre/Post Execution:
Override initialize() and terminate():
protected function initialize(InputInterface $input, OutputInterface $output)
{
$this->getOutput()->writeln('Initializing worker...');
}
protected function terminate(InputInterface $input, OutputInterface $output, $code = 0)
{
$this->getOutput()->writeln('Worker stopped with code: ' . $code);
}
Environment-Specific Config: Use Laravel’s config to toggle worker behavior:
if ($this->app->config->get('worker.enabled')) {
$this->run(function () { /* ... */ });
}
How can I help you explore Laravel packages today?