ulabox/gearman-bundle
Symfony bundle that integrates Gearman into PHP applications, letting you configure job servers, register workers, and dispatch background jobs asynchronously. Adds service definitions, console commands, and event hooks for building scalable queue-based task processing.
First, a reality check: this is a Symfony bundle, not a Laravel package. It plugs into Symfony's DI container via a Bundle class and Extension/CompilerPass wiring that Laravel will not process. So "leverage this in Laravel" means one of two things:
gearman PECL extension or gearman/gearman client.src/ into an app/Gearman/ namespace and wire them yourself with a Laravel service provider.Option 1 is almost always the right call — the bundle's value is the worker runtime and annotation/attribute job registration, not the client side.
Minimal steps for the Symfony side:
composer require ulabox/gearman-bundle
// config/bundles.php
Ulabox\GearmanBundle\GearmanBundle::class => ['all' => true],
# config/packages/gearman.yaml
gearman:
servers:
- { host: gearmand, port: 4730 }
Then run worker commands from the bundle's Command/ directory — typically something like bin/console gearman:worker:execute and gearman:worker:list.
Where to look first:
DependencyInjection/Configuration.php — the authoritative list of config keys (servers, timeouts, default worker settings). Don't guess from READMEs.Command/ — the console entry points you'll actually run in Supervisor.Annotation/ (or Attribute/ on newer forks) — how jobs declare themselves; this dictates naming conventions.Service/ (or Gearman/) — the client/worker wrappers you may want to lift into Laravel.First use case: define one job (e.g. App\Jobs\SendWelcomeEmail annotated with a Gearman job/work name), dispatch it from Laravel with $client->doBackground('send_welcome_email', json_encode($payload)), and run a single worker under Supervisor. Prove the name-matching and payload contract before scaling out.
Producer/consumer split. Keep Laravel as a pure producer. Use the PECL GearmanClient (or the pure-PHP gearman/gearman) in a small Laravel service so you avoid depending on this bundle at all on the app side:
namespace App\Services;
use GearmanClient;
class GearmanDispatcher
{
public function __construct(private GearmanClient $client) {}
public function dispatch(string $job, array $payload): string
{
return $this->client->doBackground($job, json_encode($payload));
}
}
Bind GearmanClient in a service provider with addServer('gearmand', 4730).
Single JSON contract. Gearman only transports strings. Define one serialization convention (json_encode/json_decode with JSON_THROW_ON_ERROR) and keep it identical on both sides. The Symfony job's execute() method receives that string — decode defensively and fail loudly on malformed payloads so Gearman can mark the job failed.
Job naming discipline. Names are plain strings matched at runtime; there's no schema. Centralise them (a JobNames enum or config map) so Laravel and the Symfony worker cannot drift. Prefix by domain (emails., reports.) to make gearmand listings readable.
Worker lifecycle under Supervisor. Long-running PHP workers leak memory. Cap jobs-per-worker (via the bundle's max-jobs option if present, otherwise exit the loop manually after N iterations) and let Supervisor restart:
[program:gearman-worker]
command=php /app/bin/console gearman:worker:execute --job=emails.send_welcome
autostart=true
autorestart=true
numprocs=4
stopwaitsecs=30
Background for throughput, foreground for latency-critical. doBackground returns immediately and is fire-and-forget; use doNormal/doHigh only where you need the response and can accept the blocking call in a request cycle. In Laravel, dispatch background jobs from queue events or after-commit hooks, not inline in the request.
Retry/idempotency is yours to build. Gearman has no retry store. Wrap job execution in try/catch, re-enqueue with a backoff marker on failure, and make side effects idempotent (dedupe keys, upserts). This is the biggest gap versus dispatch() + Horizon.
Observability. Use gearadmin --status or gearman-top scraper for queue depth, and log handle → jobName → workId in the job so you can correlate with the returned job handle from doBackground.
composer require this into Laravel and expect it to work. The bundle has no service provider, and its Symfony Extension/CompilerPass classes will never run. Either isolate it in a Symfony process or lift the source into your own namespace.composer update across Symfony majors. Pin the version and vendor a copy if you build on it.gearman requires libgearman-dev at build time and is not maintained against recent PHP versions. Budget for compile issues in Docker images; the pure-PHP gearman/gearman client is a fallback for the producer side.doBackground succeeds even with zero workers — the job sits in the in-memory queue only; a gearmand restart loses it. Do not treat it as your system of record. Persist intent in the DB first, then enqueue.doctrine/annotations and a configured job directory; jobs outside that autoload path are silently invisible to gearman:worker:list. Always verify with the list command before debugging a "job never runs" report.Configuration.php for timeout/iterations keys — the default blocking work() call can hang a Supervisor slot indefinitely if the job blocks. Prefer the non-blocking pattern with a short timeout, or ensure the job has its own I/O timeouts.DateTimeImmutable with timezones can round-trip badly through JSON. Normalise DTOs to scalar arrays with explicit ISO-8601 strings.GEARMAN_VERBOSE=1 on a one-off worker run plus a doNormal producer (blocking) is far faster than watching logs through Supervisor; swap to doBackground once the happy path works.Horizon, running Gearman in parallel means two retry semantics and two monitoring surfaces. Justify it (e.g. binary/streaming workloads that Gearman handles well) or consolidate on one.How can I help you explore Laravel packages today?