crazy-goat/workerman-bundle
Symfony bundle integrating Workerman to run a high-performance async HTTP server, scheduler and supervisor in pure PHP. Keeps the Symfony kernel/container alive between requests for faster apps. Supports SO_REUSEPORT and optional direct Request creation for speed.
Install the Bundle
composer require crazy-goat/workerman-bundle
Enable in config/bundles.php:
CrazyGoat\WorkermanBundle\WorkermanBundle::class => ['all' => true],
Configure the Server
Define a basic HTTP server in config/packages/workerman.yaml:
workerman:
servers:
- name: 'Symfony HTTP Server'
listen: 'http://0.0.0.0:8080'
processes: 4
Start the Server
bin/console workerman:server start
For daemon mode (detached):
bin/console workerman:server start -d
Replace php-fpm + nginx with a single Workerman process:
// src/Controller/ApiController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class ApiController extends AbstractController {
public function index(): Response {
return new Response('Hello, Workerman!');
}
}
Access via http://localhost:8080/api.Development Workflow
file_monitor reload strategy for hot-reloading:
workerman:
reload_strategy:
file_monitor:
active: true
php-inotify for efficient file monitoring:
pecl install inotify
Production Workflow
-d flag) with a reverse proxy (e.g., Nginx).workerman:
user: www-data
group: www-data
bin/console workerman:phar create
Task Scheduling
use CrazyGoat\WorkermanBundle\Scheduler\Schedule;
#[Schedule('*/5 * * * *')] // Every 5 minutes
public function cleanupDatabase(): void {
// Task logic
}
services:
App\Command\CleanupCommand:
tags: ['workerman.scheduler']
arguments:
$schedule: 'PT1H' # Every hour
Static Files: Use StaticFilesMiddleware to serve assets:
services:
workerman.middleware.static_files:
class: CrazyGoat\WorkermanBundle\Middleware\StaticFilesMiddleware
arguments:
$rootDirectory: '%kernel.project_dir%/public'
Register in workerman.yaml under middlewares.
WebSockets: Add a WebSocket server:
workerman:
servers:
- name: 'WebSocket Server'
listen: 'ws://0.0.0.0:8081'
processes: 2
GRPC Support: Enable fork support for grpc extension:
export GRPC_ENABLE_FORK_SUPPORT=1
bin/console workerman:server start
Port Binding
<1024 requires root or CAP_NET_BIND_SERVICE.8080).Memory Leaks
memory reload strategy:
workerman:
reload_strategy:
memory:
active: true
limit: 268435456 # 256 MB
File Monitoring
php-inotify, polling mode is CPU-intensive.php-inotify:
pecl install inotify
GRPC Deadlocks
GRPC_ENABLE_FORK_SUPPORT=1 before starting Workerman.Middleware Order
Check Connections:
bin/console workerman:server connections
Look for ESTABLISHED connections with high Recv-Q/Send-Q (potential hangs).
Logs:
var/log/workerman.log.stdout_file to capture echo/var_dump output:
workerman:
stdout_file: '%kernel.project_dir%/var/log/workerman.stdout.log'
Graceful Reloads:
-g flag for graceful stops/reloads to avoid connection drops:
bin/console workerman:server reload -g
Custom Reboot Strategies
Implement RebootStrategyInterface for custom reload logic:
use CrazyGoat\WorkermanBundle\Reboot\RebootStrategyInterface;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
#[AutoconfigureTag('workerman.reboot_strategy')]
class CustomRebootStrategy implements RebootStrategyInterface {
public function shouldReboot(): bool {
return someCondition();
}
}
Custom Middlewares Create middleware for request/response manipulation:
use CrazyGoat\WorkermanBundle\Middleware\MiddlewareInterface;
use CrazyGoat\WorkermanBundle\Http\Request;
use Workerman\Protocols\Http\Response;
class LoggingMiddleware implements MiddlewareInterface {
public function __invoke(Request $request, callable $next): Response {
// Pre-processing
$response = $next($request);
// Post-processing
return $response;
}
}
Register in services.yaml and workerman.yaml.
Event Listeners
Listen to Workerman events (e.g., WorkerStart, WorkerStop):
use CrazyGoat\WorkermanBundle\Event\WorkerEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: 'workerman.worker.start', method: 'onWorkerStart')]
public function onWorkerStart(WorkerEvent $event): void {
// Handle worker start
}
reuse_port for kernel-level load balancing (Linux):
workerman:
servers:
- name: 'HTTP Server'
listen: 'http://0.0.0.0:8080'
reuse_port: true
pecl install php-event
processes: 4 and adjust based on CPU cores (e.g., 2 * CPU cores).export WORKERMAN_RUNTIME_DIR=/custom/path
export WORKERMAN_CACHE_WARMUP_TIMEOUT=60
runtime_dir defaults to the PHAR’s directory. Ensure writable paths:
workerman:
runtime_dir: '/tmp/workerman_runtime'
workerman:
trusted_hosts: ['^example\.com$', '^localhost$']
How can I help you explore Laravel packages today?