Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Workerman Bundle Laravel Package

luzrain/workerman-bundle

Symfony bundle integrating Workerman, the async event-driven PHP server, so you can run HTTP, WebSocket, and custom workers configured through Symfony's dependency injection and managed with console commands.

View on GitHub
Deep Wiki
Context7

Getting Started

What you get. A Workerman runtime for Symfony: your kernel boots once, stays in memory, and serves HTTP requests (and any custom worker loops you register) from a pool of forked PHP processes — no nginx/php-fpm in front. It's the same architectural slot as FrankenPHP, RoadRunner, or Swoole runtimes, and it plugs into symfony/runtime, so the rest of your app is unchanged. As of v0.4.0 the bundle supports both Workerman 4 and Workerman 5, and exposes reuse_port for socket-level zero-downtime restarts.

Minimal setup.

  1. composer require luzrain/workerman-bundle (needs PHP 8.1+, ext-pcntl/ext-posix on Linux/macOS; not viable on Windows).
  2. Register Luzrain\WorkermanBundle\WorkermanBundle in config/bundles.php.
  3. Create config/packages/workerman.yaml with the basics — listen address/port, worker count (start with 1, tune to CPU cores later), pid file, log target, and run-as user/group if you drop privileges.
  4. Point the entry point at the bundle's runtime. With symfony/runtime installed this is a one-line change in public/index.php: return the bundle's RuntimeInterface implementation from the closure instead of the default one (copy the exact snippet from the README — see the caveat below). Alternatively pin it globally via extra.runtime.class in composer.json.
  5. Start it with the bundle's console command and curl the port. Run php bin/console list workerman (or debug:container --tag=...) to discover the exact command and tag names for the version you installed.

Where to look first. This is a ~29-star package with a single maintainer and 0 known dependents, so treat the README as the source of truth and the bundle's DependencyInjection/Configuration.php as the real documentation — it enumerates every option node and is far more current than any blog post. Second stop: bin/console debug:container filtered by the bundle's worker tag, which tells you what worker types are registered out of the box. Third stop after v0.4.0: composer show workerman/workerman — confirm which major actually resolved before you write any code that touches Workerman\Worker directly.

First real use case. Don't start by migrating your whole monolith. Pick a small JSON API or internal service, run it behind Workerman, and confirm: boot time is now one-time, request handling works, and $_SERVER['REMOTE_ADDR'] is populated from your load balancer (trusted proxies still need configuring). The second thing to try is a scheduled/cron-style task, because that's the feature that most differentiates this bundle from a plain "swap php-fpm" runtime.

Version caveat: the public API (command names, config keys, the runtime class namespace) has moved between releases; the current line is v0.4.0. The bundle now spans two Workerman majors, so the exact behaviour depends on which one Composer resolves — verify every literal name below against your installed version before pasting.

Implementation Patterns

Thin controllers, no superglobals. Under Workerman there is no $_GET/$_SERVER/$_SESSION per-request lifecycle you can rely on. Read everything from the injected Request. Anything that assumes a fresh PHP process per request — getenv() at runtime, ini_set(), set_time_limit(), header() — is a bug. Emit headers only through the Response object.

Custom background workers as services. The typical pattern: write a class that owns a long-running loop (queue consumer, WebSocket handler, TCP listener, metrics pusher), register it as a service, and tag it so the bundle forks a dedicated worker for it. Give each worker its own count in config. Keep the loop body small and delegate to ordinary injectable services, so the logic stays unit-testable without booting Workerman at all.

Scheduled tasks. Use the bundle's cron-style scheduling (attributes on service methods, or config-declared intervals) rather than shelling out to system cron. Two rules make this safe: make every task idempotent and bounded (it can overlap with itself if it runs long), and wrap cross-host tasks in symfony/lock so a second machine doesn't duplicate the work.

One container, many processes. Everything in the container is shared conceptually but forked physically — each worker gets its own copy. That means: in-memory caches (local array caches, ArrayAdapter, compiled regex caches, Doctrine\ORM identity map) survive across requests. Anything you register must be safe to keep alive. Implement ResetInterface (tagged kernel.reset) on any service that accumulates per-request state; Symfony's services_resetter handles the framework's own services, but not yours.

Long-lived clients are the payoff. Configure HttpClient, Redis, AMQP, and DB connections as normal services and let them persist. This is where the performance win lives — no connection setup per request. Add explicit reconnect/backoff in your worker loops and a ping health check; a silently dead Redis socket is the most common production failure in this architecture.

Deployment shape. Build the container in CI (cache:warmup with the prod env, not at boot on the server), ship the artifact, then restart workers with the bundle's stop/reload signal. Run it under systemd or as a Docker CMD; make sure SIGTERM handling finishes in-flight requests within a configured stop timeout. For zero-downtime, either listen on a second port and flip the load balancer, or — new in v0.4.0 — enable reuse_port so a second master can bind the same port: start the new instance, wait until its health check passes, then gracefully stop the old one. reuse_port (SO_REUSEPORT) lets the kernel load-balance across both masters during the overlap, which removes the LB config flip from your deploy script.

Dev loop. In development, run the server in a foreground terminal with logs to stdout and restart it on change — Workerman does not hot-reload PHP files by default. Keep symfony serve for quick UI iteration and only switch to the Workerman runtime when you're testing something runtime-specific.

Gotchas and Tips

  • The container is frozen at boot. Editing .env, service config, or any PHP file requires a worker restart. On deploy, always cache:clear/cache:warmup and restart — a stale cached container is the #1 "my fix didn't apply" cause here.
  • count multiplies everything. With count: 4 you have four schedulers, four consumers, four warm-up routines. Set count: 1 for anything that must be a singleton, and check the bundle's designated-worker behaviour for the scheduler before assuming it's deduplicated for you.
  • reuse_port is a sharp tool. It only makes sense with an explicit lifecycle: one master starting, one draining. Because the kernel silently distributes connections across every process bound to the port, a forgotten second instance in dev or a double-start in a broken deploy unit gives you duplicated schedulers and doubled queue consumers with no error message — validate that exactly one old + one new master are alive, and never enable it in local dev. Linux 3.9+ is required, and the option is a no-op on platforms whose SO_REUSEPORT semantics differ (macOS); test the actual restart path on the OS you deploy to. Health-check readiness must gate the drain of the old master, otherwise in-flight requests die mid-restart.
  • Workerman 4 vs 5 is now a real decision. The bundle supports both, so the transitive workerman/workerman constraint in your lock file decides your runtime behaviour. Workerman 5 changed several APIs and event-loop backends compared to v4; if your custom workers touch Workerman\Worker, Timer, or event-loop classes directly, a major bump is a breaking change for your code, not for the bundle. Pin the major explicitly in composer.json, read the Workerman changelog on upgrade, and smoke-test custom workers (not just the HTTP runtime) before rolling out.
  • Doctrine. Clear the EntityManager periodically ($em->clear()) in long loops; after a failed flush the EM is closed and subsequent calls throw — catch it and reset via ManagerRegistry::resetManager(). In dev, disable the SQL logger and the profiler entirely; both grow unboundedly in a worker process.
  • Memory creep is the default, not the exception. Watch RSS over hours, not minutes. Disable debug data collectors in prod, avoid storing request data on $this, and consider gc_collect_cycles() on an interval. A 2 MB leak per request is invisible in tests and fatal in a day.
  • Debugging. dump() works (var-dumper's dump server over TCP), but dd() and exit/die will kill the worker and, depending on config, take the whole pool with it. Prefer the bundle's log file plus stdout; use ps -ef --forest to confirm the fork tree and worker count actually match your config — this is also how you spot a stray master left behind by a reuse_port restart.
  • Exceptions in a loop stop the loop. There's no framework between your worker body and the process — wrap the body in try/catch(\Throwable), log, sleep briefly, and continue. An uncaught throwable in a consumer means silent message loss.
  • Connection math. count × pool_size must stay under your database's max_connections. Twenty workers with a 10-connection pool is 200 connections from one host; this is the classic post-migration outage. Temporarily doubling it during a reuse_port overlap makes the spike worse — size for 2× your steady-state worker count.
  • File uploads and temp files need cleanup — tmpfile/upload temp dirs accumulate because the process never exits to trigger cleanup. Delete explicitly in a finally.
  • Extension points worth knowing: a custom runtime class implementing RuntimeInterface (to add boot-time wiring), custom worker factories registered by tag, and the bundle's lifecycle events. If the package's API doesn't cover a need, a custom worker factory is usually a smaller change than patching the bundle.
  • Bus factor. ~29 stars, one maintainer, zero dependents, small and infrequent release cadence. Pin the version (both the bundle and the Workerman major), read the changelog before upgrading, and keep your Workerman-specific code (runtime wiring, worker classes, scheduling attributes) in a thin layer so a swap to FrankenPHP or RoadRunner later is a contained diff rather than a rewrite.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console