mmoreram/gearman-bundle
Mmoreram GearmanBundle integrates Gearman with Symfony to run background jobs and asynchronous tasks. It helps define workers, manage job queues, and dispatch work from your PHP application using simple configuration and service-based worker definitions.
Decision point first: this is a Symfony bundle (Mmoreram\GearmanBundle), not a Laravel package. It ships a Bundle class, a DI extension, and compiler passes, so composer require mmoreram/gearman-bundle into a Laravel app buys you nothing usable — no service provider, no config publish, no queue driver. Day-to-day leverage for a Laravel developer comes in two forms:
gearman:work command plus a thin client wrapper around ext-gearman).Prerequisites either way:
# Server
docker run -d -p 4730:4730 --name gearmand artefactual/gearmand
# PHP extension (NOT the pure-PHP "gearman" composer lib)
pecl install gearman && docker-php-ext-enable gearman
php -m | grep gearman
Minimal Symfony-side flow (what "first use case" looks like):
composer require mmoreram/gearman-bundle # v5.1.1 as of this writing
# config/packages/gearman.yaml
gearman:
servers:
localhost:4730: ~
namespace App\Worker;
use Mmoreram\GearmanBundle\Driver\Gearman;
class ImageWorker
{
#[Gearman\Job(name: 'image.resize')]
public function resize(string $payload): string
{
$data = json_decode($payload, true);
// ... resize ...
return json_encode(['ok' => true, 'path' => $data['out']]);
}
}
bin/console gearman:worker:list # discovery check — do this FIRST
bin/console gearman:worker:execute ImageWorker
bin/console gearman:call image.resize '{"src":"a.jpg","out":"b.jpg"}'
The first real use case is always the same: move something slow and non-interactive (thumbnailing, PDF generation, mail fan-out, webhook retries) out of the request cycle, and get a CLI you can supervise.
Before you composer require, check the dependency floor. v5.1.1 requires doctrine/annotations ^2.0. If anything else in the Symfony worker service still pins ^1.x, composer will resolve you back to v5.0.1 — decide deliberately which side wins rather than letting the solver pick.
Worker class = job namespace. Each public method on a worker class becomes a Gearman function; the method name (or the attribute name) is what clients call. Grouping related jobs in one class is the idiomatic unit, because it maps 1:1 to a supervised process.
Discovery, not registration. The bundle scans worker classes (annotations/attributes, plus optionally tagged services) rather than making you wire every job in YAML. That is the feature worth copying in Laravel — a workers config array or attribute scan beats a hand-maintained registry. Prefer attribute-based discovery (#[Gearman\Job]) over docblock annotations: it needs no annotation reader at all, so the whole doctrine/annotations upgrade treadmill (which is exactly what 5.1.1 was) simply doesn't apply to you.
Client usage from your app code — inject the bundle's client service rather than instantiating \GearmanClient directly, so server config stays in one place:
public function __construct(private GearmanClient $client) {}
// fire and forget
$this->client->doBackground('image.resize', json_encode($payload));
// synchronous, with a result
$result = $this->client->doNormal('image.resize', json_encode($payload));
Rules of thumb I'd apply daily:
doBackground by default. Sync calls tie a web request to a worker; only use them for sub-100 ms jobs.['id' => ..., 'v' => 1, 'data' => ...]) so you can evolve it. Never rely on positional args.unique keys for idempotent dedupe (e.g. md5('resize:'.$imageId)) so a double-dispatch doesn't double-process.iterations set so PHP recycles the process and bleeds memory/DB connections. Never run workers with daemonize semantics you don't control.Bridging to Laravel. If you keep Gearman, the cleanest Laravel shape is a custom queue connector (Queue::extend) so dispatch() keeps working, plus an artisan gearman:work <worker> command that mirrors gearman:worker:execute. If you don't need Gearman specifically, Laravel's Redis/SQS queue already gives you what this bundle's CLI gives you, with retries and a failed-jobs table baked in — be honest about whether you're adopting Gearman because of an existing gearmand fleet or because of the bundle.
ext-gearman is a hard dependency and a common silent failure. Installing gearman/gearman from Packagist instead gets you a different API. If GearmanClient is "not found" at runtime, it's the extension.doctrine/annotations 2.0 bump plus the refactor needed to fit it. Read it as signal, not capability: nothing new to adopt, but it raises the floor on the annotation path.doctrine/annotations 2.0 removed APIs that older bootstraps call. The deprecated AnnotationRegistry autoloading helpers are gone; annotation classes are resolved purely through composer autoloading now. If your worker-service bootstrap (or a bundle you copied it from) calls AnnotationRegistry::registerLoader(), it fatals on upgrade. Attributes sidestep this entirely.doctrine/annotations ^1.x will block v5.1.1. Check with composer why doctrine/annotations before bumping, and be prepared to hold at v5.0.1 in the worker service while you migrate the conflicting package — nothing in the wire protocol or job API changed, so mixed versions across services are fine.failed_jobs, queue:retry, Horizon-style metrics — you build yourself. Budget for it.iterations and let supervisor restart; treat a worker as disposable.app/console, Acme\DemoBundle). On modern Symfony use attributes and bin/console; the 5.1.1 refactor modernised the code behind those annotations but not the documentation around them.image.resize declared in two worker classes is a race you'll debug at 2am. gearman:worker:list is your friend; grep job names in CI.gearadmin --status, gearadmin --workers, gearadmin --show-jobs, plus gearmand -vvv. Run a worker in the foreground and var_dump before you blame the bundle.app/Workers scan rather than fighting the Symfony DI compiler pass.How can I help you explore Laravel packages today?