tourze/symfony-workerman-bundle
A Symfony bundle that integrates Workerman into Symfony applications, helping you run and manage persistent, event-driven Workerman workers and servers alongside your existing Symfony services, configuration, and console commands with minimal setup.
The first thing to establish: despite showing up in a Laravel-oriented review queue, tourze/symfony-workerman-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config/workerman.php, and no facade. Treat it as a Symfony building block that you either (a) run inside a Symfony app alongside your Laravel service, or (b) mine for its wiring ideas and use workerman/workerman directly in Laravel.
Minimal steps in a Symfony host:
composer require tourze/symfony-workerman-bundle:0.0.1 — pin the exact version. At 0.0.1 there is no BC promise and the changelog is a single auto-generated link.config/bundles.php (Tourze\SymfonyWorkermanBundle\SymfonyWorkermanBundle::class => ['all' => true]). Flex auto-registration only happens if a recipe exists; assume it does not and register manually.DependencyInjection/Configuration.php before writing any config. In a 0.0.1 bundle this file is the only reliable documentation of what the config tree actually accepts — node names, defaults, and required keys.DependencyInjection/SymfonyWorkermanBundleExtension.php next, to see which services are registered unconditionally vs. behind a config flag, and what tags it looks for.bin/console list and grep for workerman to find the entry-point command. That command is your first use case: start a single long-running worker in the foreground, confirm it boots and binds a port, then build from there.First real use case: a long-lived TCP/HTTP/WebSocket listener where you want Symfony's container to supply the handlers (repositories, loggers, HTTP clients) instead of hand-rolling new calls inside a Worker::onMessage closure.
For Laravel specifically: a Laravel-flavoured equivalent is a custom Artisan command wrapping Worker::runAll(), or Octane/RoadRunner if you only need HTTP. Do not expect Octane-style request sandboxing from this bundle.
Worker-per-command. The idiomatic shape is one console command (or one configured worker entry) per logical server. Keep the Worker construction declarative and the behaviour in injected services — the bundle exists to let the container own those services.
Handlers as tagged services. The leverage you get from a bundle over raw Workerman is DI. Look for a tag (e.g. a worker/event tag) in the extension and register your onMessage / onConnect / onWorkerStart handlers as services with that tag. That keeps handlers unit-testable and injectable, and lets you swap implementations per environment.
Bootstrap-once, reset-per-request. The container is compiled once at boot and then lives for hours. Anything request-scoped must be reset. Wire Symfony's kernel.reset / services_resetter into your message loop, and explicitly clear accumulated state (Doctrine EntityManager::clear(), Monolog buffers, in-memory caches) on an interval or per message. This is the single most important pattern for a long-running worker and it is not something a 0.0.1 bundle will do for you.
Config-driven worker definitions. Put worker counts, listen addresses, and process settings in config/packages/*.yaml under the bundle's root key so dev/staging/prod differ without code edits. Read the config tree first — unknown keys are usually a hard failure, not a warning.
Integration with Symfony Messenger. The natural pairing: Workerman holds the socket and pushes payloads onto a Messenger transport (Redis/AMQP), and messenger:consume workers do the heavy lifting. This keeps your long-running socket process thin and lets Messenger handle retries and failure transport. Avoid doing blocking DB/HTTP work directly in onMessage — one slow handler stalls every connection on that worker.
Supervisor/systemd over -d. Do not daemonize inside the process. Run foreground under systemd or Supervisor with Restart=always, so restarts, logs, and exit codes are managed outside PHP. In containers, foreground is the only sane mode.
Deploy workflow. Because PHP code is loaded once, deploys need an explicit reload/restart step (reload for graceful, restart for hard). Put that in your deploy script next to cache:clear — deploying without it silently keeps serving old code.
0.0.1 exactly, read the source, and expect to re-read it on every bump. Budget for a fork-and-maintain scenario.opcache.validate_timestamps=0 in production is faster but means code changes require a full restart, not a reload.EntityManager permanently for that process. Either reset it per message or catch and re-open it. Same story for any service that latches error state.echo is a debugging trap. Under Supervisor/systemd stdout goes to the journal, but buffering and worker interleaving make output unreliable in production. Use the injected LoggerInterface.EADDRINUSE after a crash usually means an orphaned child process — check ps for stale workers before restarting. Multiple workers binding the same port needs reusePort on Linux; Windows has no fork, so worker counts > 1 won't behave as expected.reload waits for in-flight connections, so a stuck handler blocks the reload indefinitely. Know your timeout, and keep a restart path available.cache:clear effects. Restart the worker after DI/config changes, or you will debug a phantom.config/services.yaml. Avoid subclassing bundle internals — at 0.0.1 those classes are the most likely to move.Worker instance. If it is thin, you are paying bundle-shaped coupling for something a 60-line Artisan/console command would do more transparently.How can I help you explore Laravel packages today?