Installation:
composer require cesurapp/swoole-bundle
Update public/index.php to include the entrypoint:
require_once dirname(__DIR__).'/vendor/cesurapp/swoole-bundle/src/Runtime/entrypoint.php';
Basic Configuration:
Add to config/packages/swoole.yaml:
swoole:
entrypoint: public/index.php
watch_dir: /config,/src,/templates
watch_extension: '*.php,*.yaml,*.yml,*.twig'
First Use Case: Start the server in development mode (with file watcher):
bin/console server:watch
Verify it’s running:
bin/console server:status
Replace Symfony HTTP Client:
Enable replace_http_client: true in swoole.yaml to leverage Swoole’s async HTTP client for external requests.
// Example: Async HTTP request in a controller
$client = $this->container->get('swoole.http_client');
$response = $client->get('https://api.example.com/data');
Static File Handling: Enable static file serving via config:
swoole:
http_settings:
enable_static_handler: true
Dispatch Tasks:
Use TaskHandler in controllers/services:
$this->taskHandler->dispatch(MyTask::class, ['data' => 'payload']);
task_sync_mode: true in swoole.yaml for blocking calls (e.g., for critical operations).Task Retries:
Configure retries in swoole.yaml:
swoole:
failed_task_retry: '@EveryMinute10'
failed_task_attempt: 3
View failed tasks:
bin/console task:failed:view
Define Cron Jobs:
Extend AbstractCronJob and use predefined expressions:
class SendDailyReportCron extends AbstractCronJob {
public string $TIME = '@daily';
public bool $ENABLE = true;
public function __invoke(): void {
// Logic here
}
}
Register the job in services.yaml:
services:
App\Cron\SendDailyReportCron: ~
Run Manually:
bin/console cron:run App\Cron\SendDailyReportCron
class RedisConsumerProcess extends AbstractProcessJob {
public bool $ENABLE = true;
public bool $RESTART = true;
public int $RESTART_DELAY = 5;
public function __invoke(): void {
$this->redis->subscribe(['queue'], fn($redis, $channel, $msg) => {
// Process message
});
}
}
Register in services.yaml:
services:
App\Process\RedisConsumerProcess: ~
Handler Setup:
Implement initServerEvents in your handler:
class ChatWebSocketHandler {
public function initServerEvents(Server $server): void {
$server->on('message', fn($server, Frame $frame) => {
$server->push($frame->fd, "Echo: {$frame->data}");
});
}
}
Configure in swoole.yaml:
swoole:
websocket_handler: App\WebSocket\ChatWebSocketHandler
Dependency Injection:
Use constructor injection for services (e.g., LoggerInterface, ChatService).
Serialization Limits:
serialize()/unserialize()).$this->taskHandler->dispatch(MyTask::class, [
'user' => $user->toArray(), // Custom method
]);
Cron Locking:
@EveryMinute5 and @EveryMinute10) for parallel jobs.WebSocket State:
$frame->fd) in Redis for broadcasting.Process Worker Crashes:
RESTART = true.bin/console server:status
Or tail Swoole logs:
tail -f var/log/swoole.log
HTTP Client Replacement:
replace_http_client affects all HTTP requests (Symfony HTTP Client, Guzzle, etc.).Server Status:
bin/console server:status
Task Debugging:
bin/console task:failed:view
bin/console task:failed:retry
Log Levels:
log_level in swoole.yaml (e.g., 4 for SWOOLE_LOG_WARNING).1: SWOOLE_LOG_DEBUG4: SWOOLE_LOG_WARNING5: SWOOLE_LOG_ERRORDevelopment Mode:
server:watch for auto-reloads during development.vendor/ and var/ by default.Custom Task Middleware:
TaskHandler to add pre/post-processing:
class CustomTaskHandler extends TaskHandler {
public function dispatch(string $task, array $data): void {
// Pre-process data
$data['timestamp'] = time();
parent::dispatch($task, $data);
}
}
services.yaml:
services:
App\Service\CustomTaskHandler: ~
WebSocket Authentication:
open event:
$server->on('open', function($server, $request) {
if (!$this->authService->validate($request->header)) {
$server->disconnect($request->fd);
}
});
Dynamic Cron Jobs:
CronJobLoader:
class DatabaseCronJobLoader implements CronJobLoaderInterface {
public function load(): array {
return $this->entityManager->getRepository(CronJob::class)->findAll();
}
}
swoole.cron_job_loader.Task Result Handling:
task_sync_mode: true for synchronous tasks and capture results:
$result = $this->taskHandler->dispatchSync(MyTask::class, ['data' => 'payload']);
Worker Count:
worker_num = CPU cores. Adjust in .env:
SERVER_HTTP_SETTINGS_WORKER_NUM=4
worker_num = CPU cores * 2 for high-traffic apps.Task Worker Limits:
task_worker_num defaults to CPU cores / 2. Increase for heavy async tasks:
SERVER_HTTP_SETTINGS_TASK_WORKER_NUM=4
Memory Leaks:
Swoole\Process::signal() to trigger cleanup.# config/packages/swoole.yaml (prod)
swoole:
watch_dir: null # Disable in production
How can I help you explore Laravel packages today?