[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8459":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":37,"readmeContent":38,"aiSummary":39,"trendingCount":16,"starSnapshotCount":16,"syncStatus":40,"lastSyncTime":41,"discoverSource":42},8459,"laravel-s","hhxsv5\u002Flaravel-s","hhxsv5","LaravelS is an out-of-the-box adapter between Laravel\u002FLumen and Swoole.","",null,"PHP",3883,466,189,66,0,1,30.01,"MIT License",false,"PHP-8.x",true,[24,25,26,27,28,29,30,31,32,33,34,35,36],"async","http","laravel","lumen","performance","process","server","swoole","task","tcp","timer","udp","websocket","2026-06-12 02:01:54","\u003Cdiv align=\"center\">\n    \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fraw\u002FPHP-8.x\u002Flogo.svg\" alt=\"LaravelS Logo\" height=\"80\">\n     \u003Cp>\n        \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md\">English Docs\u003C\u002Fa> |\n        \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME-CN.md\">中文文档\u003C\u002Fa>\n    \u003C\u002Fp>\n    \u003Cp>🚀 LaravelS is an out-of-the-box adapter between Laravel\u002FLumen and Swoole\u003C\u002Fp>\n    \u003Cp>\n        \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Freleases\">\n            \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Frelease\u002Fhhxsv5\u002Flaravel-s.svg\" alt=\"Latest Version\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fwww.php.net\u002F\">\n            \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fpackagist\u002Fphp-v\u002Fhhxsv5\u002Flaravel-s\" alt=\"PHP Version\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fswoole\u002Fswoole-src\">\n            \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fswoole-%3E=5.0.0-flat.svg\" alt=\"Swoole Version\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fhhxsv5\u002Flaravel-s\u002Fstats\">\n            \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fpackagist\u002Fdt\u002Fhhxsv5\u002Flaravel-s\" alt=\"Total Downloads\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fscrutinizer-ci.com\u002Fg\u002Fhhxsv5\u002Flaravel-s\u002F\">\n            \u003Cimg src=\"https:\u002F\u002Fscrutinizer-ci.com\u002Fg\u002Fhhxsv5\u002Flaravel-s\u002Fbadges\u002Fbuild.png?b=PHP-8.x\" alt=\"Build Status\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fscrutinizer-ci.com\u002Fg\u002Fhhxsv5\u002Flaravel-s\u002F\">\n            \u003Cimg src=\"https:\u002F\u002Fscrutinizer-ci.com\u002Fg\u002Fhhxsv5\u002Flaravel-s\u002Fbadges\u002Fcode-intelligence.svg?b=PHP-8.x\" alt=\"Code Intelligence Status\">\n        \u003C\u002Fa>\n        \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FLICENSE\">\n            \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flicense\u002Fhhxsv5\u002Flaravel-s\" alt=\"License\">\n        \u003C\u002Fa>\n    \u003C\u002Fp>\n\u003C\u002Fdiv>\n\n---\n\n## Continuous Updates\n- *Please `Watch` this repository to get the latest updates.*\n\nTable of Contents\n=================\n\n* [Features](#features)\n* [Benchmark](#benchmark)\n* [Requirements](#requirements)\n* [Install](#install)\n* [Run](#run)\n* [Deploy](#deploy)\n* [Cooperate with Nginx (Recommended)](#cooperate-with-nginx-recommended)\n* [Cooperate with Apache](#cooperate-with-apache)\n* [Enable WebSocket server](#enable-websocket-server)\n* [Listen events](#listen-events)\n    * [System events](#system-events)\n    * [Customized asynchronous events](#customized-asynchronous-events)\n* [Asynchronous task queue](#asynchronous-task-queue)\n* [Millisecond cron job](#millisecond-cron-job)\n* [Automatically reload after modifying code](#automatically-reload-after-modifying-code)\n* [Get the instance of SwooleServer in your project](#get-the-instance-of-swooleserver-in-your-project)\n* [Use SwooleTable](#use-swooletable)\n* [Multi-port mixed protocol](#multi-port-mixed-protocol)\n* [Coroutine](#coroutine)\n* [Custom process](#custom-process)\n* [Common components](#common-components)\n    * [Apollo](#apollo)\n    * [Prometheus](#prometheus)\n* [Other features](#other-features)\n    * [Configure Swoole events](#configure-swoole-events)\n    * [Serverless](#serverless)\n* [Important notices](#important-notices)\n* [Users and cases](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME-CN.md#%E7%94%A8%E6%88%B7%E4%B8%8E%E6%A1%88%E4%BE%8B)\n* [Alternatives](#alternatives)\n* [Sponsor](#sponsor)\n* [Star History](#star-history)\n* [License](#license)\n\n## Features\n\n- Built-in Http\u002F[WebSocket](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#enable-websocket-server) server\n\n- [Multi-port mixed protocol](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#multi-port-mixed-protocol)\n\n- [Custom process](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#custom-process)\n\n- Memory resident\n\n- [Asynchronous event listening](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#customized-asynchronous-events)\n\n- [Asynchronous task queue](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#asynchronous-task-queue)\n\n- [Millisecond cron job](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#millisecond-cron-job)\n\n- [Common Components](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#common-components)\n\n- Gracefully reload\n\n- [Automatically reload after modifying code](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#automatically-reload-after-modifying-code)\n\n- Support Laravel\u002FLumen both, good compatibility\n\n- Simple & Out of the box\n\n## Benchmark\n\n- [Which is the fastest web framework?](https:\u002F\u002Fgithub.com\u002Fthe-benchmarker\u002Fweb-frameworks)\n\n- [TechEmpower Framework Benchmarks](https:\u002F\u002Fwww.techempower.com\u002Fbenchmarks\u002F)\n\n## Requirements\n\n| Dependency | Requirement |\n| -------- | -------- |\n| [PHP](https:\u002F\u002Fsecure.php.net\u002F) | `>=8.2` `Enable extension intl` |\n| [Swoole](https:\u002F\u002Fwww.swoole.co.uk\u002F) | `>=5.0` |\n| [Laravel](https:\u002F\u002Flaravel.com\u002F)\u002F[Lumen](https:\u002F\u002Flumen.laravel.com\u002F) | `>=10` |\n\n## Install\n\n1.Require package via [Composer](https:\u002F\u002Fgetcomposer.org\u002F)([packagist](https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fhhxsv5\u002Flaravel-s)).\n```bash\n# PHP >=8.2\ncomposer require \"hhxsv5\u002Flaravel-s:~3.8.0\"\n\n# PHP >=5.5.9,\u003C=7.4.33\n# composer require \"hhxsv5\u002Flaravel-s:~3.7.0\"\n\n# Make sure that your composer.lock file is under the VCS\n```\n\n2.Register service provider(pick one of two).\n\n- `Laravel`: in `config\u002Fapp.php` file, `Laravel 5.5+ supports package discovery automatically, you should skip this step`\n    ```php\n    'providers' => [\n        \u002F\u002F...\n        Hhxsv5\\LaravelS\\Illuminate\\LaravelSServiceProvider::class,\n    ],\n    ```\n\n- `Lumen`: in `bootstrap\u002Fapp.php` file\n    ```php\n    $app->register(Hhxsv5\\LaravelS\\Illuminate\\LaravelSServiceProvider::class);\n    ```\n\n3.Publish configuration and binaries.\n> *After upgrading LaravelS, you need to republish; click [here](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Freleases) to see the change notes of each version.*\n\n```bash\nphp artisan laravels publish\n# Configuration: config\u002Flaravels.php\n# Binary: bin\u002Flaravels bin\u002Ffswatch bin\u002Finotify\n```\n\n4.Change `config\u002Flaravels.php`: listen_ip, listen_port, refer [Settings](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FSettings.md).\n\n5.Performance tuning\n\n- [Adjust kernel parameters](https:\u002F\u002Fwiki.swoole.com\u002F#\u002Fother\u002Fsysctl?id=%e5%86%85%e6%a0%b8%e5%8f%82%e6%95%b0%e8%b0%83%e6%95%b4)\n\n- [Number of Workers](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration#worker_num): LaravelS uses Swoole's `Synchronous IO` mode, the larger the `worker_num` setting, the better the concurrency performance, but it will cause more memory usage and process switching overhead. If one request takes 100ms, in order to provide 1000QPS concurrency, at least 100 Worker processes need to be configured. The calculation method is: worker_num = 1000QPS\u002F(1s\u002F1ms) = 100, so incremental pressure testing is needed to calculate the best` worker_num`.\n\n- [Number of Task Workers](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration#task_worker_num)\n\n## Run\n> `Please read the notices carefully before running`, [Important notices](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s#important-notices)(IMPORTANT).\n\n- Commands: `php bin\u002Flaravels {start|stop|restart|reload|info|help}`.\n\n| Command | Description |\n| --------- | --------- |\n| start | Start LaravelS, list the processes by \"*ps -ef&#124;grep laravels*\" |\n| stop | Stop LaravelS, and trigger the method `onStop` of Custom process |\n| restart | Restart LaravelS: Stop gracefully before starting; The service is `unavailable` until startup is complete |\n| reload | Reload all Task\u002FWorker\u002FTimer processes which contain your business codes, and trigger the method `onReload` of Custom process, CANNOT reload Master\u002FManger processes. After modifying `config\u002Flaravels.php`, you `only` have to call `restart` to restart |\n| info | Display component version information |\n| help | Display help information |\n\n- Boot options for the commands `start` and `restart`.\n\n| Option | Description |\n| --------- | --------- |\n| -d&#124;--daemonize | Run as a daemon, this option will override the `swoole.daemonize` setting in `laravels.php` |\n| -e&#124;--env | The environment the command should run under, such as `--env=testing` will use the configuration file `.env.testing` firstly, this feature requires Laravel 5.2+ |\n| -i&#124;--ignore | Ignore checking PID file of Master process |\n| -x&#124;--x-version | The version(branch) of the current project, stored in $_ENV\u002F$_SERVER, access via `$_ENV['X_VERSION']` `$_SERVER['X_VERSION']` `$request->server->get('X_VERSION')` |\n\n- `Runtime` files: `start` will automatically execute `php artisan laravels config` and generate these files, developers generally don't need to pay attention to them, it's recommended to add them to `.gitignore`.\n\n| File | Description |\n| --------- | --------- |\n| storage\u002Flaravels.conf | LaravelS's `runtime` configuration file |\n| storage\u002Flaravels.pid | PID file of Master process |\n| storage\u002Flaravels-timer-process.pid | PID file of the Timer process |\n| storage\u002Flaravels-custom-processes.pid | PID file of all custom processes |\n\n## Deploy\n> It is recommended to supervise the main process through [Supervisord](http:\u002F\u002Fsupervisord.org\u002F), the premise is without option `-d` and to set `swoole.daemonize` to `false`.\n\n```\n[program:laravel-s-test]\ndirectory=\u002Fvar\u002Fwww\u002Flaravel-s-test\ncommand=\u002Fusr\u002Flocal\u002Fbin\u002Fphp bin\u002Flaravels start -i\nnumprocs=1\nautostart=true\nautorestart=true\nstartretries=3\nuser=www-data\nredirect_stderr=true\nstdout_logfile=\u002Fvar\u002Flog\u002Fsupervisor\u002F%(program_name)s.log\n```\n\n## Cooperate with Nginx (Recommended)\n> [Demo](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Fdocker\u002Fblob\u002Fmaster\u002Fnginx\u002Fconf.d\u002Flaravels.conf).\n\n```nginx\ngzip on;\ngzip_min_length 1024;\ngzip_comp_level 2;\ngzip_types text\u002Fplain text\u002Fcss text\u002Fjavascript application\u002Fjson application\u002Fjavascript application\u002Fx-javascript application\u002Fxml application\u002Fx-httpd-php image\u002Fjpeg image\u002Fgif image\u002Fpng font\u002Fttf font\u002Fotf image\u002Fsvg+xml;\ngzip_vary on;\ngzip_disable \"msie6\";\nupstream swoole {\n    # Connect IP:Port\n    server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;\n    # Connect UnixSocket Stream file, tips: put the socket file in the \u002Fdev\u002Fshm directory to get better performance\n    #server unix:\u002Fyourpath\u002Flaravel-s-test\u002Fstorage\u002Flaravels.sock weight=5 max_fails=3 fail_timeout=30s;\n    #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;\n    #server 192.168.1.2:5200 backup;\n    keepalive 16;\n}\nserver {\n    listen 80;\n    # Don't forget to bind the host\n    server_name laravels.com;\n    root \u002Fyourpath\u002Flaravel-s-test\u002Fpublic;\n    access_log \u002Fyourpath\u002Flog\u002Fnginx\u002F$server_name.access.log  main;\n    autoindex off;\n    index index.html index.htm;\n    # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.\n    location \u002F {\n        try_files $uri @laravels;\n    }\n    # Response 404 directly when request the PHP file, to avoid exposing public\u002F*.php\n    #location ~* \\.php$ {\n    #    return 404;\n    #}\n    location @laravels {\n        # proxy_connect_timeout 60s;\n        # proxy_send_timeout 60s;\n        # proxy_read_timeout 120s;\n        proxy_http_version 1.1;\n        proxy_set_header Connection \"\";\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Real-PORT $remote_port;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $http_host;\n        proxy_set_header Scheme $scheme;\n        proxy_set_header Server-Protocol $server_protocol;\n        proxy_set_header Server-Name $server_name;\n        proxy_set_header Server-Addr $server_addr;\n        proxy_set_header Server-Port $server_port;\n        # \"swoole\" is the upstream\n        proxy_pass http:\u002F\u002Fswoole;\n    }\n}\n```\n\n## Cooperate with Apache\n\n```apache\nLoadModule proxy_module \u002Fyourpath\u002Fmodules\u002Fmod_proxy.so\nLoadModule proxy_balancer_module \u002Fyourpath\u002Fmodules\u002Fmod_proxy_balancer.so\nLoadModule lbmethod_byrequests_module \u002Fyourpath\u002Fmodules\u002Fmod_lbmethod_byrequests.so\nLoadModule proxy_http_module \u002Fyourpath\u002Fmodules\u002Fmod_proxy_http.so\nLoadModule slotmem_shm_module \u002Fyourpath\u002Fmodules\u002Fmod_slotmem_shm.so\nLoadModule rewrite_module \u002Fyourpath\u002Fmodules\u002Fmod_rewrite.so\nLoadModule remoteip_module \u002Fyourpath\u002Fmodules\u002Fmod_remoteip.so\nLoadModule deflate_module \u002Fyourpath\u002Fmodules\u002Fmod_deflate.so\n\n\u003CIfModule deflate_module>\n    SetOutputFilter DEFLATE\n    DeflateCompressionLevel 2\n    AddOutputFilterByType DEFLATE text\u002Fhtml text\u002Fplain text\u002Fcss text\u002Fjavascript application\u002Fjson application\u002Fjavascript application\u002Fx-javascript application\u002Fxml application\u002Fx-httpd-php image\u002Fjpeg image\u002Fgif image\u002Fpng font\u002Fttf font\u002Fotf image\u002Fsvg+xml\n\u003C\u002FIfModule>\n\n\u003CVirtualHost *:80>\n    # Don't forget to bind the host\n    ServerName www.laravels.com\n    ServerAdmin hhxsv5@sina.com\n\n    DocumentRoot \u002Fyourpath\u002Flaravel-s-test\u002Fpublic;\n    DirectoryIndex index.html index.htm\n    \u003CDirectory \"\u002F\">\n        AllowOverride None\n        Require all granted\n    \u003C\u002FDirectory>\n\n    RemoteIPHeader X-Forwarded-For\n\n    ProxyRequests Off\n    ProxyPreserveHost On\n    \u003CProxy balancer:\u002F\u002Flaravels>  \n        BalancerMember http:\u002F\u002F192.168.1.1:5200 loadfactor=7\n        #BalancerMember http:\u002F\u002F192.168.1.2:5200 loadfactor=3\n        #BalancerMember http:\u002F\u002F192.168.1.3:5200 loadfactor=1 status=+H\n        ProxySet lbmethod=byrequests\n    \u003C\u002FProxy>\n    #ProxyPass \u002F balancer:\u002F\u002Flaravels\u002F\n    #ProxyPassReverse \u002F balancer:\u002F\u002Flaravels\u002F\n\n    # Apache handles the static resources, LaravelS handles the dynamic resource.\n    RewriteEngine On\n    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d\n    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f\n    RewriteRule ^\u002F(.*)$ balancer:\u002F\u002Flaravels%{REQUEST_URI} [P,L]\n\n    ErrorLog ${APACHE_LOG_DIR}\u002Fwww.laravels.com.error.log\n    CustomLog ${APACHE_LOG_DIR}\u002Fwww.laravels.com.access.log combined\n\u003C\u002FVirtualHost>\n```\n\n## Enable WebSocket server\n> The Listening address of WebSocket Sever is the same as Http Server.\n\n1.Create WebSocket Handler class, and implement interface `WebSocketHandlerInterface`.The instant is automatically instantiated when start, you do not need to manually create it.\n```php\nnamespace App\\Services;\nuse Hhxsv5\\LaravelS\\Swoole\\WebSocketHandlerInterface;\nuse Swoole\\Http\\Request;\nuse Swoole\\Http\\Response;\nuse Swoole\\WebSocket\\Frame;\nuse Swoole\\WebSocket\\Server;\n\u002F**\n * @see https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-websocket-server\n *\u002F\nclass WebSocketService implements WebSocketHandlerInterface\n{\n    \u002F\u002F Declare constructor without parameters\n    public function __construct()\n    {\n    }\n    \u002F\u002F public function onHandShake(Request $request, Response $response)\n    \u002F\u002F {\n           \u002F\u002F Custom handshake: https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-websocket-server-on-handshake\n           \u002F\u002F The onOpen event will be triggered automatically after a successful handshake\n    \u002F\u002F }\n    public function onOpen(Server $server, Request $request)\n    {\n        \u002F\u002F Before the onOpen event is triggered, the HTTP request to establish the WebSocket has passed the Laravel route,\n        \u002F\u002F so Laravel's Request, Auth information are readable, Session is readable and writable, but only in the onOpen event.\n        \u002F\u002F \\Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n        $server->push($request->fd, 'Welcome to LaravelS');\n    }\n    public function onMessage(Server $server, Frame $frame)\n    {\n        \u002F\u002F \\Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]);\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n        $server->push($frame->fd, date('Y-m-d H:i:s'));\n    }\n    public function onClose(Server $server, $fd, $reactorId)\n    {\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n    }\n}\n```\n\n2.Modify `config\u002Flaravels.php`.\n```php\n\u002F\u002F ...\n'websocket'      => [\n    'enable'  => true, \u002F\u002F Note: set enable to true\n    'handler' => \\App\\Services\\WebSocketService::class,\n],\n'swoole'         => [\n    \u002F\u002F...\n    \u002F\u002F Must set dispatch_mode in (2, 4, 5), see https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration\n    'dispatch_mode' => 2,\n    \u002F\u002F...\n],\n\u002F\u002F ...\n```\n3.Use `SwooleTable` to bind FD & UserId, optional, [Swoole Table Demo](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FREADME.md#use-swooletable). Also you can use the other global storage services, like Redis\u002FMemcached\u002FMySQL, but be careful that FD will be possible conflicting between multiple `Swoole Servers`.\n\n4.Cooperate with Nginx (Recommended)\n> Refer [WebSocket Proxy](http:\u002F\u002Fnginx.org\u002Fen\u002Fdocs\u002Fhttp\u002Fwebsocket.html)\n\n```nginx\nmap $http_upgrade $connection_upgrade {\n    default upgrade;\n    ''      close;\n}\nupstream swoole {\n    # Connect IP:Port\n    server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;\n    # Connect UnixSocket Stream file, tips: put the socket file in the \u002Fdev\u002Fshm directory to get better performance\n    #server unix:\u002Fyourpath\u002Flaravel-s-test\u002Fstorage\u002Flaravels.sock weight=5 max_fails=3 fail_timeout=30s;\n    #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;\n    #server 192.168.1.2:5200 backup;\n    keepalive 16;\n}\nserver {\n    listen 80;\n    # Don't forget to bind the host\n    server_name laravels.com;\n    root \u002Fyourpath\u002Flaravel-s-test\u002Fpublic;\n    access_log \u002Fyourpath\u002Flog\u002Fnginx\u002F$server_name.access.log  main;\n    autoindex off;\n    index index.html index.htm;\n    # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.\n    location \u002F {\n        try_files $uri @laravels;\n    }\n    # Response 404 directly when request the PHP file, to avoid exposing public\u002F*.php\n    #location ~* \\.php$ {\n    #    return 404;\n    #}\n    # Http and WebSocket are concomitant, Nginx identifies them by \"location\"\n    # !!! The location of WebSocket is \"\u002Fws\"\n    # Javascript: var ws = new WebSocket(\"ws:\u002F\u002Flaravels.com\u002Fws\");\n    location =\u002Fws {\n        # proxy_connect_timeout 60s;\n        # proxy_send_timeout 60s;\n        # proxy_read_timeout: Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole.\n        # proxy_read_timeout 60s;\n        proxy_http_version 1.1;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Real-PORT $remote_port;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $http_host;\n        proxy_set_header Scheme $scheme;\n        proxy_set_header Server-Protocol $server_protocol;\n        proxy_set_header Server-Name $server_name;\n        proxy_set_header Server-Addr $server_addr;\n        proxy_set_header Server-Port $server_port;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection $connection_upgrade;\n        proxy_pass http:\u002F\u002Fswoole;\n    }\n    location @laravels {\n        # proxy_connect_timeout 60s;\n        # proxy_send_timeout 60s;\n        # proxy_read_timeout 60s;\n        proxy_http_version 1.1;\n        proxy_set_header Connection \"\";\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Real-PORT $remote_port;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $http_host;\n        proxy_set_header Scheme $scheme;\n        proxy_set_header Server-Protocol $server_protocol;\n        proxy_set_header Server-Name $server_name;\n        proxy_set_header Server-Addr $server_addr;\n        proxy_set_header Server-Port $server_port;\n        proxy_pass http:\u002F\u002Fswoole;\n    }\n}\n```\n\n5.Heartbeat setting\n\n- Heartbeat setting of Swoole\n\n    ```php\n    \u002F\u002F config\u002Flaravels.php\n    'swoole' => [\n        \u002F\u002F...\n        \u002F\u002F All connections are traversed every 60 seconds. If a connection does not send any data to the server within 600 seconds, the connection will be forced to close.\n        'heartbeat_idle_time'      => 600,\n        'heartbeat_check_interval' => 60,\n        \u002F\u002F...\n    ],\n    ```\n\n- Proxy read timeout of Nginx\n\n    ```nginx\n    # Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds\n    proxy_read_timeout 60s;\n    ```\n\n6.Push data in controller\n\n```php\nnamespace App\\Http\\Controllers;\nclass TestController extends Controller\n{\n    public function push()\n    {\n        $fd = 1; \u002F\u002F Find fd by userId from a map [userId=>fd].\n        \u002F**@var \\Swoole\\WebSocket\\Server $swoole *\u002F\n        $swoole = app('swoole');\n        $success = $swoole->push($fd, 'Push data to fd#1 in Controller');\n        var_dump($success);\n    }\n}\n```\n\n## Listen events\n\n### System events\n> Usually, you can reset\u002Fdestroy some `global\u002Fstatic` variables, or change the current `Request\u002FResponse` object.\n\n- `laravels.received_request` After LaravelS parsed `Swoole\\Http\\Request` to `Illuminate\\Http\\Request`, before Laravel's Kernel handles this request.\n\n    ```php\n    \u002F\u002F Edit file `app\u002FProviders\u002FEventServiceProvider.php`, add the following code into method `boot`\n    \u002F\u002F If no variable $events, you can also call Facade \\Event::listen(). \n    $events->listen('laravels.received_request', function (\\Illuminate\\Http\\Request $req, $app) {\n        $req->query->set('get_key', 'hhxsv5');\u002F\u002F Change query of request\n        $req->request->set('post_key', 'hhxsv5'); \u002F\u002F Change post of request\n    });\n    ```\n\n- `laravels.generated_response` After Laravel's Kernel handled the request, before LaravelS parses `Illuminate\\Http\\Response` to `Swoole\\Http\\Response`.\n\n    ```php\n    \u002F\u002F Edit file `app\u002FProviders\u002FEventServiceProvider.php`, add the following code into method `boot`\n    \u002F\u002F If no variable $events, you can also call Facade \\Event::listen(). \n    $events->listen('laravels.generated_response', function (\\Illuminate\\Http\\Request $req, \\Symfony\\Component\\HttpFoundation\\Response $rsp, $app) {\n        $rsp->headers->set('header-key', 'hhxsv5');\u002F\u002F Change header of response\n    });\n    ```\n\n### Customized asynchronous events\n> This feature depends on `AsyncTask` of `Swoole`, your need to set `swoole.task_worker_num` in `config\u002Flaravels.php` firstly. The performance of asynchronous event processing is influenced by number of Swoole task process, you need to set [task_worker_num](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration) appropriately.\n\n1.Create event class.\n```php\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Event;\nclass TestEvent extends Event\n{\n    protected $listeners = [\n        \u002F\u002F Listener list\n        TestListener1::class,\n        \u002F\u002F TestListener2::class,\n    ];\n    private $data;\n    public function __construct($data)\n    {\n        $this->data = $data;\n    }\n    public function getData()\n    {\n        return $this->data;\n    }\n}\n```\n\n2.Create listener class.\n```php\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Event;\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Task;\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Listener;\nclass TestListener1 extends Listener\n{\n    public function handle(Event $event)\n    {\n        \\Log::info(__CLASS__ . ':handle start', [$event->getData()]);\n        sleep(2);\u002F\u002F Simulate the slow codes\n        \u002F\u002F Deliver task in CronJob, but NOT support callback finish() of task.\n        \u002F\u002F Note: Modify task_ipc_mode to 1 or 2 in config\u002Flaravels.php, see https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration\n        $ret = Task::deliver(new TestTask('task data'));\n        var_dump($ret);\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n        \u002F\u002F return false; \u002F\u002F Stop propagating this event to subsequent listeners\n    }\n}\n```\n\n3.Fire event.\n```php\n\u002F\u002F Create instance of event and fire it, \"fire\" is asynchronous.\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Event;\n$event = new TestEvent('event data');\n\u002F\u002F $event->delay(10); \u002F\u002F Delay 10 seconds to fire event\n\u002F\u002F $event->setTries(3); \u002F\u002F When an error occurs, try 3 times in total\n$success = Event::fire($event);\nvar_dump($success);\u002F\u002F Return true if sucess, otherwise false\n```\n\n## Asynchronous task queue\n> This feature depends on `AsyncTask` of `Swoole`, your need to set `swoole.task_worker_num` in `config\u002Flaravels.php` firstly. The performance of task processing is influenced by number of Swoole task process, you need to set [task_worker_num](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration) appropriately.\n\n1.Create task class.\n```php\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Task;\nclass TestTask extends Task\n{\n    private $data;\n    private $result;\n    public function __construct($data)\n    {\n        $this->data = $data;\n    }\n    \u002F\u002F The logic of task handling, run in task process, CAN NOT deliver task\n    public function handle()\n    {\n        \\Log::info(__CLASS__ . ':handle start', [$this->data]);\n        sleep(2);\u002F\u002F Simulate the slow codes\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n        $this->result = 'the result of ' . $this->data;\n    }\n    \u002F\u002F Optional, finish event, the logic of after task handling, run in worker process, CAN deliver task \n    public function finish()\n    {\n        \\Log::info(__CLASS__ . ':finish start', [$this->result]);\n        Task::deliver(new TestTask2('task2 data')); \u002F\u002F Deliver the other task\n    }\n}\n```\n\n2.Deliver task.\n```php\n\u002F\u002F Create instance of TestTask and deliver it, \"deliver\" is asynchronous.\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Task;\n$task = new TestTask('task data');\n\u002F\u002F $task->delay(3);\u002F\u002F delay 3 seconds to deliver task\n\u002F\u002F $task->setTries(3); \u002F\u002F When an error occurs, try 3 times in total\n$ret = Task::deliver($task);\nvar_dump($ret);\u002F\u002F Return true if sucess, otherwise false\n```\n\n## Millisecond cron job\n> Wrapper cron job base on [Swoole's Millisecond Timer](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-async-io), replace `Linux` `Crontab`.\n\n1.Create cron job class.\n```php\nnamespace App\\Jobs\\Timer;\nuse App\\Tasks\\TestTask;\nuse Swoole\\Coroutine;\nuse Hhxsv5\\LaravelS\\Swoole\\Task\\Task;\nuse Hhxsv5\\LaravelS\\Swoole\\Timer\\CronJob;\nclass TestCronJob extends CronJob\n{\n    protected $i = 0;\n    \u002F\u002F !!! The `interval` and `isImmediate` of cron job can be configured in two ways(pick one of two): one is to overload the corresponding method, and the other is to pass parameters when registering cron job.\n    \u002F\u002F --- Override the corresponding method to return the configuration: begin\n    public function interval()\n    {\n        return 1000;\u002F\u002F Run every 1000ms\n    }\n    public function isImmediate()\n    {\n        return false;\u002F\u002F Whether to trigger `run` immediately after setting up\n    }\n    \u002F\u002F --- Override the corresponding method to return the configuration: end\n    public function run()\n    {\n        \\Log::info(__METHOD__, ['start', $this->i, microtime(true)]);\n        \u002F\u002F do something\n        \u002F\u002F sleep(1); \u002F\u002F Swoole \u003C 2.1\n        Coroutine::sleep(1); \u002F\u002F Swoole>=2.1 Coroutine will be automatically created for run().\n        $this->i++;\n        \\Log::info(__METHOD__, ['end', $this->i, microtime(true)]);\n\n        if ($this->i >= 10) { \u002F\u002F Run 10 times only\n            \\Log::info(__METHOD__, ['stop', $this->i, microtime(true)]);\n            $this->stop(); \u002F\u002F Stop this cron job, but it will run again after restart\u002Freload.\n            \u002F\u002F Deliver task in CronJob, but NOT support callback finish() of task.\n            \u002F\u002F Note: Modify task_ipc_mode to 1 or 2 in config\u002Flaravels.php, see https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration\n            $ret = Task::deliver(new TestTask('task data'));\n            var_dump($ret);\n        }\n        \u002F\u002F The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try\u002Fcatch manually.\n    }\n}\n```\n\n2.Register cron job.\n```php\n\u002F\u002F Register cron jobs in file \"config\u002Flaravels.php\"\n[\n    \u002F\u002F ...\n    'timer'          => [\n        'enable' => true, \u002F\u002F Enable Timer\n        'jobs'   => [ \u002F\u002F The list of cron job\n            \u002F\u002F Enable LaravelScheduleJob to run `php artisan schedule:run` every 1 minute, replace Linux Crontab\n            \u002F\u002F \\Hhxsv5\\LaravelS\\Illuminate\\LaravelScheduleJob::class,\n            \u002F\u002F Two ways to configure parameters:\n            \u002F\u002F [\\App\\Jobs\\Timer\\TestCronJob::class, [1000, true]], \u002F\u002F Pass in parameters when registering\n            \\App\\Jobs\\Timer\\TestCronJob::class, \u002F\u002F Override the corresponding method to return the configuration\n        ],\n        'max_wait_time' => 5, \u002F\u002F Max waiting time of reloading\n        \u002F\u002F Enable the global lock to ensure that only one instance starts the timer when deploying multiple instances. This feature depends on Redis, please see https:\u002F\u002Flaravel.com\u002Fdocs\u002F7.x\u002Fredis\n        'global_lock'     => false,\n        'global_lock_key' => config('app.name', 'Laravel'),\n    ],\n    \u002F\u002F ...\n];\n```\n\n3.Note: it will launch multiple timers when build the server cluster, so you need to make sure that launch one timer only to avoid running repetitive task.\n\n4.LaravelS `v3.4.0` starts to support the hot restart [Reload] `Timer` process. After LaravelS receives the `SIGUSR1` signal, it waits for `max_wait_time`(default 5) seconds to end the process, then the `Manager` process will pull up the `Timer` process again.\n\n5.If you only need to use `minute-level` scheduled tasks, it is recommended to enable `Hhxsv5\\LaravelS\\Illuminate\\LaravelScheduleJob` instead of Linux Crontab, so that you can follow the coding habits of [Laravel task scheduling](https:\u002F\u002Flaravel.com\u002Fdocs\u002F7.x\u002Fscheduling) and configure `Kernel`.\n\n```php\n\u002F\u002F app\u002FConsole\u002FKernel.php\nprotected function schedule(Schedule $schedule)\n{\n    \u002F\u002F runInBackground() will start a new child process to execute the task. This is asynchronous and will not affect the execution timing of other tasks.\n    $schedule->command(TestCommand::class)->runInBackground()->everyMinute();\n}\n```\n\n## Automatically reload after modifying code\n\n- Via `inotify`, support Linux only.\n\n    1.Install [inotify](http:\u002F\u002Fpecl.php.net\u002Fpackage\u002Finotify) extension.\n\n    2.Turn on the switch in [Settings](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FSettings.md#inotify_reloadenable).\n\n    3.Notice: Modify the file only in `Linux` to receive the file change events. It's recommended to use the latest Docker. [Vagrant Solution](https:\u002F\u002Fgithub.com\u002Fmhallin\u002Fvagrant-notify-forwarder).\n\n- Via `fswatch`, support OS X\u002FLinux\u002FWindows.\n\n    1.Install [fswatch](https:\u002F\u002Fgithub.com\u002Femcrisostomo\u002Ffswatch).\n\n    2.Run command in your project root directory.\n\n    ```bash\n    # Watch current directory\n    .\u002Fbin\u002Ffswatch\n    # Watch app directory\n    .\u002Fbin\u002Ffswatch .\u002Fapp\n    ```\n\n- Via `inotifywait`, support Linux.\n\n    1.Install [inotify-tools](https:\u002F\u002Fgithub.com\u002Frvoicilas\u002Finotify-tools).\n\n    2.Run command in your project root directory.\n\n    ```bash\n    # Watch current directory\n    .\u002Fbin\u002Finotify\n    # Watch app directory\n    .\u002Fbin\u002Finotify .\u002Fapp\n    ```\n\n- When the above methods does not work, the ultimate solution: set `max_request=1,worker_num=1`, so that `Worker` process will restart after processing a request. The performance of this method is very poor, `so only development environment use`.\n\n## Get the instance of `SwooleServer` in your project\n\n```php\n\u002F**\n * $swoole is the instance of `Swoole\\WebSocket\\Server` if enable WebSocket server, otherwise `Swoole\\Http\\Server`\n * @var \\Swoole\\WebSocket\\Server|\\Swoole\\Http\\Server $swoole\n *\u002F\n$swoole = app('swoole');\nvar_dump($swoole->stats());\n$swoole->push($fd, 'Push WebSocket message');\n```\n\n## Use `SwooleTable`\n\n1.Define Table, support multiple.\n> All defined tables will be created before Swoole starting.\n\n```php\n\u002F\u002F in file \"config\u002Flaravels.php\"\n[\n    \u002F\u002F ...\n    'swoole_tables'  => [\n        \u002F\u002F Scene：bind UserId & FD in WebSocket\n        'ws' => [\u002F\u002F The Key is table name, will add suffix \"Table\" to avoid naming conflicts. Here defined a table named \"wsTable\"\n            'size'   => 102400,\u002F\u002F The max size\n            'column' => [\u002F\u002F Define the columns\n                ['name' => 'value', 'type' => \\Swoole\\Table::TYPE_INT, 'size' => 8],\n            ],\n        ],\n        \u002F\u002F...Define the other tables\n    ],\n    \u002F\u002F ...\n];\n```\n\n2.Access `Table`: all table instances will be bound on `SwooleServer`, access by `app('swoole')->xxxTable`.\n\n```php\nnamespace App\\Services;\nuse Hhxsv5\\LaravelS\\Swoole\\WebSocketHandlerInterface;\nuse Swoole\\Http\\Request;\nuse Swoole\\WebSocket\\Frame;\nuse Swoole\\WebSocket\\Server;\nclass WebSocketService implements WebSocketHandlerInterface\n{\n    \u002F**@var \\Swoole\\Table $wsTable *\u002F\n    private $wsTable;\n    public function __construct()\n    {\n        $this->wsTable = app('swoole')->wsTable;\n    }\n    \u002F\u002F Scene：bind UserId & FD in WebSocket\n    public function onOpen(Server $server, Request $request)\n    {\n        \u002F\u002F var_dump(app('swoole') === $server);\u002F\u002F The same instance\n        \u002F**\n         * Get the currently logged in user\n         * This feature requires that the path to establish a WebSocket connection go through middleware such as Authenticate.\n         * E.g:\n         * Browser side: var ws = new WebSocket(\"ws:\u002F\u002F127.0.0.1:5200\u002Fws\");\n         * Then the \u002Fws route in Laravel needs to add the middleware like Authenticate.\n         * Route::get('\u002Fws', function () {\n         *     \u002F\u002F Respond any content with status code 200\n         *     return 'websocket';\n         * })->middleware(['auth']);\n         *\u002F\n        \u002F\u002F $user = Auth::user();\n        \u002F\u002F $userId = $user ? $user->id : 0; \u002F\u002F 0 means a guest user who is not logged in\n        $userId = mt_rand(1000, 10000);\n        \u002F\u002F if (!$userId) {\n        \u002F\u002F     \u002F\u002F Disconnect the connections of unlogged users\n        \u002F\u002F     $server->disconnect($request->fd);\n        \u002F\u002F     return;\n        \u002F\u002F }\n        $this->wsTable->set('uid:' . $userId, ['value' => $request->fd]);\u002F\u002F Bind map uid to fd\n        $this->wsTable->set('fd:' . $request->fd, ['value' => $userId]);\u002F\u002F Bind map fd to uid\n        $server->push($request->fd, \"Welcome to LaravelS #{$request->fd}\");\n    }\n    public function onMessage(Server $server, Frame $frame)\n    {\n        \u002F\u002F Broadcast\n        foreach ($this->wsTable as $key => $row) {\n            if (strpos($key, 'uid:') === 0 && $server->isEstablished($row['value'])) {\n                $content = sprintf('Broadcast: new message \"%s\" from #%d', $frame->data, $frame->fd);\n                $server->push($row['value'], $content);\n            }\n        }\n    }\n    public function onClose(Server $server, $fd, $reactorId)\n    {\n        $uid = $this->wsTable->get('fd:' . $fd);\n        if ($uid !== false) {\n            $this->wsTable->del('uid:' . $uid['value']); \u002F\u002F Unbind uid map\n        }\n        $this->wsTable->del('fd:' . $fd);\u002F\u002F Unbind fd map\n        $server->push($fd, \"Goodbye #{$fd}\");\n    }\n}\n```\n\n## Multi-port mixed protocol\n\n> For more information, please refer to [Swoole Server AddListener](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server-methods#swoole_server-addlistener)\n\nTo make our main server support more protocols not just Http and WebSocket, we bring the feature `multi-port mixed protocol` of Swoole in LaravelS and name it `Socket`. Now, you can build `TCP\u002FUDP` applications easily on top of Laravel.\n\n1. Create `Socket` handler class, and extend `Hhxsv5\\LaravelS\\Swoole\\Socket\\{TcpSocket|UdpSocket|Http|WebSocket}`.\n\n    ```php\n    namespace App\\Sockets;\n    use Hhxsv5\\LaravelS\\Swoole\\Socket\\TcpSocket;\n    use Swoole\\Server;\n    class TestTcpSocket extends TcpSocket\n    {\n        public function onConnect(Server $server, $fd, $reactorId)\n        {\n            \\Log::info('New TCP connection', [$fd]);\n            $server->send($fd, 'Welcome to LaravelS.');\n        }\n        public function onReceive(Server $server, $fd, $reactorId, $data)\n        {\n            \\Log::info('Received data', [$fd, $data]);\n            $server->send($fd, 'LaravelS: ' . $data);\n            if ($data === \"quit\\r\\n\") {\n                $server->send($fd, 'LaravelS: bye' . PHP_EOL);\n                $server->close($fd);\n            }\n        }\n        public function onClose(Server $server, $fd, $reactorId)\n        {\n            \\Log::info('Close TCP connection', [$fd]);\n            $server->send($fd, 'Goodbye');\n        }\n    }\n    ```\n\n    These `Socket` connections share the same worker processes with your `HTTP`\u002F`WebSocket` connections. So it won't be a problem at all if you want to deliver tasks, use `SwooleTable`, even Laravel components such as DB, Eloquent and so on.\n    At the same time, you can access `Swoole\\Server\\Port` object directly by member property `swoolePort`.\n\n    ```php\n    public function onReceive(Server $server, $fd, $reactorId, $data)\n    {\n        $port = $this->swoolePort; \u002F\u002F Get the `Swoole\\Server\\Port` object\n    }\n    ```\n\n    ```php\n    namespace App\\Http\\Controllers;\n    class TestController extends Controller\n    {\n        public function test()\n        {\n            \u002F**@var \\Swoole\\Http\\Server|\\Swoole\\WebSocket\\Server $swoole *\u002F\n            $swoole = app('swoole');\n            \u002F\u002F $swoole->ports: Traverse all Port objects, https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fmultiple-ports\n            $port = $swoole->ports[0]; \u002F\u002F Get the `Swoole\\Server\\Port` object, $port[0] is the port of the main server\n            foreach ($port->connections as $fd) { \u002F\u002F Traverse all connections\n                \u002F\u002F $swoole->send($fd, 'Send tcp message');\n                \u002F\u002F if($swoole->isEstablished($fd)) {\n                \u002F\u002F     $swoole->push($fd, 'Send websocket message');\n                \u002F\u002F }\n            }\n        }\n    }\n    ```\n\n2. Register Sockets.\n\n    ```php\n    \u002F\u002F Edit `config\u002Flaravels.php`\n    \u002F\u002F...\n    'sockets' => [\n        [\n            'host'     => '127.0.0.1',\n            'port'     => 5291,\n            'type'     => SWOOLE_SOCK_TCP,\u002F\u002F Socket type: SWOOLE_SOCK_TCP\u002FSWOOLE_SOCK_TCP6\u002FSWOOLE_SOCK_UDP\u002FSWOOLE_SOCK_UDP6\u002FSWOOLE_UNIX_DGRAM\u002FSWOOLE_UNIX_STREAM\n            'settings' => [\u002F\u002F Swoole settings：https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server-methods#swoole_server-addlistener\n                'open_eof_check' => true,\n                'package_eof'    => \"\\r\\n\",\n            ],\n            'handler'  => \\App\\Sockets\\TestTcpSocket::class,\n            'enable'   => true, \u002F\u002F whether to enable, default true\n        ],\n    ],\n    ```\n\n    About the heartbeat configuration, it can only be set on the `main server` and cannot be configured on `Socket`, but the `Socket` inherits the heartbeat configuration of the `main server`.\n\n    For TCP socket, `onConnect` and `onClose` events will be blocked when `dispatch_mode` of Swoole is `1\u002F3`, so if you want to unblock these two events please set `dispatch_mode` to `2\u002F4\u002F5`.\n\n    ```php\n    'swoole' => [\n        \u002F\u002F...\n        'dispatch_mode' => 2,\n        \u002F\u002F...\n    ];\n    ```\n\n3. Test.\n\n- TCP: `telnet 127.0.0.1 5291`\n\n- UDP: [Linux] `echo \"Hello LaravelS\" > \u002Fdev\u002Fudp\u002F127.0.0.1\u002F5292`\n\n4. Register example of other protocols.\n\n    - UDP\n    ```php\n    'sockets' => [\n        [\n            'host'     => '0.0.0.0',\n            'port'     => 5292,\n            'type'     => SWOOLE_SOCK_UDP,\n            'settings' => [\n                'open_eof_check' => true,\n                'package_eof'    => \"\\r\\n\",\n            ],\n            'handler'  => \\App\\Sockets\\TestUdpSocket::class,\n        ],\n    ],\n    ```\n\n    - Http\n    ```php\n    'sockets' => [\n        [\n            'host'     => '0.0.0.0',\n            'port'     => 5293,\n            'type'     => SWOOLE_SOCK_TCP,\n            'settings' => [\n                'open_http_protocol' => true,\n            ],\n            'handler'  => \\App\\Sockets\\TestHttp::class,\n        ],\n    ],\n    ```\n\n    - WebSocket: The main server must `turn on WebSocket`, that is, set `websocket.enable` to `true`.\n    ```php\n    'sockets' => [\n        [\n            'host'     => '0.0.0.0',\n            'port'     => 5294,\n            'type'     => SWOOLE_SOCK_TCP,\n            'settings' => [\n                'open_http_protocol'      => true,\n                'open_websocket_protocol' => true,\n            ],\n            'handler'  => \\App\\Sockets\\TestWebSocket::class,\n        ],\n    ],\n    ```\n\n## Coroutine\n\n> [Swoole Coroutine](https:\u002F\u002Fwww.swoole.co.uk\u002Fcoroutine)\n\n- Warning: The order of code execution in the coroutine is out of order. The data of the request level should be isolated by the coroutine ID. However, there are many singleton and static attributes in Laravel\u002FLumen, the data between different requests will affect each other, it's `Unsafe`. For example, the database connection is a singleton, the same database connection shares the same PDO resource. This is fine in the synchronous blocking mode, but it does not work in the asynchronous coroutine mode. Each query needs to create different connections and maintain IO state of different connections, which requires a connection pool.\n\n- `DO NOT` enable the coroutine, only the custom process can use the coroutine.\n\n## Custom process\n\n> Support developers to create special work processes for monitoring, reporting, or other special tasks. Refer [addProcess](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server-methods#swoole_server-addprocess).\n\n1. Create Proccess class, implements CustomProcessInterface.\n\n    ```php\n    namespace App\\Processes;\n    use App\\Tasks\\TestTask;\n    use Hhxsv5\\LaravelS\\Swoole\\Process\\CustomProcessInterface;\n    use Hhxsv5\\LaravelS\\Swoole\\Task\\Task;\n    use Swoole\\Coroutine;\n    use Swoole\\Http\\Server;\n    use Swoole\\Process;\n    class TestProcess implements CustomProcessInterface\n    {\n        \u002F**\n         * @var bool Quit tag for Reload updates\n         *\u002F\n        private static $quit = false;\n\n        public static function callback(Server $swoole, Process $process)\n        {\n            \u002F\u002F The callback method cannot exit. Once exited, Manager process will automatically create the process \n            while (!self::$quit) {\n                \\Log::info('Test process: running');\n                \u002F\u002F sleep(1); \u002F\u002F Swoole \u003C 2.1\n                Coroutine::sleep(1); \u002F\u002F Swoole>=2.1: Coroutine & Runtime will be automatically enabled for callback(). Pay attention to the compatibility between the components used and the coroutines. If they are not compatible, only some coroutines can be enabled, such as: \\Swoole\\Runtime::enableCoroutine(SWOOLE_HOOK_TCP | SWOOLE_HOOK_SLEEP | SWOOLE_HOOK_FILE);\n                 \u002F\u002F Deliver task in custom process, but NOT support callback finish() of task.\n                \u002F\u002F Note: Modify task_ipc_mode to 1 or 2 in config\u002Flaravels.php, see https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration\n                $ret = Task::deliver(new TestTask('task data'));\n                var_dump($ret);\n                \u002F\u002F The upper layer will catch the exception thrown in the callback and record it in the Swoole log, and then this process will exit. The Manager process will re-create the process after 3 seconds, so developers need to try\u002Fcatch to catch the exception by themselves to avoid frequent process creation.\n                \u002F\u002F throw new \\Exception('an exception');\n            }\n        }\n        \u002F\u002F Requirements: LaravelS >= v3.4.0 & callback() must be async non-blocking program.\n        public static function onReload(Server $swoole, Process $process)\n        {\n            \u002F\u002F Stop the process...\n            \u002F\u002F Then end process\n            \\Log::info('Test process: reloading');\n            self::$quit = true;\n            \u002F\u002F $process->exit(0); \u002F\u002F Force exit process\n        }\n        \u002F\u002F Requirements: LaravelS >= v3.7.4 & callback() must be async non-blocking program.\n        public static function onStop(Server $swoole, Process $process)\n        {\n            \u002F\u002F Stop the process...\n            \u002F\u002F Then end process\n            \\Log::info('Test process: stopping');\n            self::$quit = true;\n            \u002F\u002F $process->exit(0); \u002F\u002F Force exit process\n        }\n    }\n    ```\n\n2. Register TestProcess.\n\n    ```php\n    \u002F\u002F Edit `config\u002Flaravels.php`\n    \u002F\u002F ...\n    'processes' => [\n        'test' => [ \u002F\u002F Key name is process name\n            'class'    => \\App\\Processes\\TestProcess::class,\n            'redirect' => false, \u002F\u002F Whether redirect stdin\u002Fstdout, true or false\n            'pipe'     => 0,     \u002F\u002F The type of pipeline, 0: no pipeline 1: SOCK_STREAM 2: SOCK_DGRAM\n            'enable'   => true,  \u002F\u002F Whether to enable, default true\n            \u002F\u002F'num'    => 3   \u002F\u002F To create multiple processes of this class, default is 1\n            \u002F\u002F'queue'    => [ \u002F\u002F Enable message queue as inter-process communication, configure empty array means use default parameters\n            \u002F\u002F    'msg_key'  => 0,    \u002F\u002F The key of the message queue. Default: ftok(__FILE__, 1).\n            \u002F\u002F    'mode'     => 2,    \u002F\u002F Communication mode, default is 2, which means contention mode\n            \u002F\u002F    'capacity' => 8192, \u002F\u002F The length of a single message, is limited by the operating system kernel parameters. The default is 8192, and the maximum is 65536\n            \u002F\u002F],\n            \u002F\u002F'restart_interval' => 5, \u002F\u002F After the process exits abnormally, how many seconds to wait before restarting the process, default 5 seconds\n        ],\n    ],\n    ```\n\n3. Note: The callback() cannot quit. If quit, the Manager process will re-create the process.\n\n4. Example: Write data to a custom process.\n\n    ```php\n    \u002F\u002F config\u002Flaravels.php\n    'processes' => [\n        'test' => [\n            'class'    => \\App\\Processes\\TestProcess::class,\n            'redirect' => false,\n            'pipe'     => 1,\n        ],\n    ],\n    ```\n\n    ```php\n    \u002F\u002F app\u002FProcesses\u002FTestProcess.php\n    public static function callback(Server $swoole, Process $process)\n    {\n        while ($data = $process->read()) {\n            \\Log::info('TestProcess: read data', [$data]);\n            $process->write('TestProcess: ' . $data);\n        }\n    }\n    ```\n\n    ```php\n    \u002F\u002F app\u002FHttp\u002FControllers\u002FTestController.php\n    public function testProcessWrite()\n    {\n        \u002F**@var \\Swoole\\Process[] $process *\u002F\n        $customProcesses = \\Hhxsv5\\LaravelS\\LaravelS::getCustomProcesses();\n        $process = $customProcesses['test'];\n        $process->write('TestController: write data' . time());\n        var_dump($process->read());\n    }\n    ```\n\n## Common components\n\n### Apollo\n> `LaravelS` will pull the `Apollo` configuration and write it to the `.env` file when starting. At the same time, `LaravelS` will start the custom process `apollo` to monitor the configuration and automatically `reload` when the configuration changes.\n\n1. Enable Apollo: add `--enable-apollo` and Apollo parameters to the startup parameters.\n    \n    ```bash\n    php bin\u002Flaravels start --enable-apollo --apollo-server=http:\u002F\u002F127.0.0.1:8080 --apollo-app-id=LARAVEL-S-TEST\n    ```\n\n2. Support hot updates(optional).\n\n    ```php\n    \u002F\u002F Edit `config\u002Flaravels.php`\n    'processes' => Hhxsv5\\LaravelS\\Components\\Apollo\\Process::getDefinition(),\n    ```\n\n    ```php\n    \u002F\u002F When there are other custom process configurations\n    'processes' => [\n        'test' => [\n            'class'    => \\App\\Processes\\TestProcess::class,\n            'redirect' => false,\n            'pipe'     => 1,\n        ],\n        \u002F\u002F ...\n    ] + Hhxsv5\\LaravelS\\Components\\Apollo\\Process::getDefinition(),\n    ```\n\n3. List of available parameters.\n\n| Parameter | Description | Default | Demo |\n| -------- | -------- | -------- | -------- |\n| apollo-server | Apollo server URL | - | --apollo-server=http:\u002F\u002F127.0.0.1:8080 |\n| apollo-app-id | Apollo APP ID | - | --apollo-app-id=LARAVEL-S-TEST |\n| apollo-namespaces | The namespace to which the APP belongs, support specify the multiple | application | --apollo-namespaces=application --apollo-namespaces=env |\n| apollo-cluster | The cluster to which the APP belongs | default | --apollo-cluster=default |\n| apollo-client-ip | IP of current instance, can also be used for grayscale publishing | Local intranet IP | --apollo-client-ip=10.2.1.83 |\n| apollo-pull-timeout | Timeout time(seconds) when pulling configuration | 5 | --apollo-pull-timeout=5 |\n| apollo-backup-old-env | Whether to backup the old configuration file when updating the configuration file `.env` | false | --apollo-backup-old-env |\n\n### Prometheus\n> Support Prometheus monitoring and alarm, Grafana visually view monitoring metrics. Please refer to [Docker Compose](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Fdocker) for the environment construction of Prometheus and Grafana.\n\n1. Require extension [APCu >= 5.0.0](https:\u002F\u002Fpecl.php.net\u002Fpackage\u002Fapcu), please install it by `pecl install apcu`.\n\n2. Copy the configuration file `prometheus.php` to the `config` directory of your project. Modify the configuration as appropriate.\n    ```bash\n    # Execute commands in the project root directory\n    cp vendor\u002Fhhxsv5\u002Flaravel-s\u002Fconfig\u002Fprometheus.php config\u002F\n    ```\n    If your project is `Lumen`, you also need to manually load the configuration `$app->configure('prometheus');` in `bootstrap\u002Fapp.php`.\n\n3. Configure `global` middleware: `Hhxsv5\\LaravelS\\Components\\Prometheus\\RequestMiddleware::class`. In order to count the request time consumption as accurately as possible, `RequestMiddleware` must be the `first` global middleware, which needs to be placed in front of other middleware.\n\n4. Register ServiceProvider: `Hhxsv5\\LaravelS\\Components\\Prometheus\\ServiceProvider::class`.\n\n5. Configure the CollectorProcess in `config\u002Flaravels.php` to collect the metrics of Swoole Worker\u002FTask\u002FTimer processes regularly.\n    ```php\n    'processes' => Hhxsv5\\LaravelS\\Components\\Prometheus\\CollectorProcess::getDefinition(),\n    ```\n\n6. Create the route to output metrics.\n    ```php\n    use Hhxsv5\\LaravelS\\Components\\Prometheus\\Exporter;\n\n    Route::get('\u002Factuator\u002Fprometheus', function () {\n        $result = app(Exporter::class)->render();\n        return response($result, 200, ['Content-Type' => Exporter::REDNER_MIME_TYPE]);\n    });\n    ```\n\n7. Complete the configuration of Prometheus and start it.\n    ```yml\n    global:\n      scrape_interval: 5s\n      scrape_timeout: 5s\n      evaluation_interval: 30s\n    scrape_configs:\n    - job_name: laravel-s-test\n      honor_timestamps: true\n      metrics_path: \u002Factuator\u002Fprometheus\n      scheme: http\n      follow_redirects: true\n      static_configs:\n      - targets:\n        - 127.0.0.1:5200 # The ip and port of the monitored service\n    # Dynamically discovered using one of the supported service-discovery mechanisms\n    # https:\u002F\u002Fprometheus.io\u002Fdocs\u002Fprometheus\u002Flatest\u002Fconfiguration\u002Fconfiguration\u002F#scrape_config\n    # - job_name: laravels-eureka\n    #   honor_timestamps: true\n    #   scrape_interval: 5s\n    #   metrics_path: \u002Factuator\u002Fprometheus\n    #   scheme: http\n    #   follow_redirects: true\n      # eureka_sd_configs:\n      # - server: http:\u002F\u002F127.0.0.1:8080\u002Feureka\n      #   follow_redirects: true\n      #   refresh_interval: 5s\n    ```\n\n8. Start Grafana, then import [panel json](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Ftree\u002FPHP-8.x\u002Fgrafana-dashboard.json).\n\n\u003Cimg src=\"https:\u002F\u002Fraw.githubusercontent.com\u002Fhhxsv5\u002Flaravel-s\u002FPHP-8.x\u002Fgrafana-dashboard.png\" height=\"800px\" alt=\"Grafana Dashboard\">\n\n## Other features\n\n### Configure Swoole events\n\nSupported events:\n\n| Event | Interface | When happened |\n| -------- | -------- | -------- |\n| ServerStart | Hhxsv5\\LaravelS\\Swoole\\Events\\ServerStartInterface | Occurs when the Master process is starting, `this event should not handle complex business logic, and can only do some simple work of initialization`. |\n| ServerStop | Hhxsv5\\LaravelS\\Swoole\\Events\\ServerStopInterface | Occurs when the server exits normally, `CANNOT use async or coroutine related APIs in this event`. |\n| WorkerStart | Hhxsv5\\LaravelS\\Swoole\\Events\\WorkerStartInterface | Occurs after the Worker\u002FTask process is started, and the Laravel initialization has been completed. |\n| WorkerStop | Hhxsv5\\LaravelS\\Swoole\\Events\\WorkerStopInterface | Occurs after the Worker\u002FTask process exits normally |\n| WorkerError | Hhxsv5\\LaravelS\\Swoole\\Events\\WorkerErrorInterface | Occurs when an exception or fatal error occurs in the Worker\u002FTask process |\n\n1.Create an event class to implement the corresponding interface.\n```php\nnamespace App\\Events;\nuse Hhxsv5\\LaravelS\\Swoole\\Events\\ServerStartInterface;\nuse Swoole\\Atomic;\nuse Swoole\\Http\\Server;\nclass ServerStartEvent implements ServerStartInterface\n{\n    public function __construct()\n    {\n    }\n    public function handle(Server $server)\n    {\n        \u002F\u002F Initialize a global counter (available across processes)\n        $server->atomicCount = new Atomic(2233);\n\n        \u002F\u002F Invoked in controller: app('swoole')->atomicCount->get();\n    }\n}\n```\n\n```php\nnamespace App\\Events;\nuse Hhxsv5\\LaravelS\\Swoole\\Events\\WorkerStartInterface;\nuse Swoole\\Http\\Server;\nclass WorkerStartEvent implements WorkerStartInterface\n{\n    public function __construct()\n    {\n    }\n    public function handle(Server $server, $workerId)\n    {\n        \u002F\u002F Initialize a database connection pool\n        \u002F\u002F DatabaseConnectionPool::init();\n    }\n}\n```\n2.Configuration.\n```php\n\u002F\u002F Edit `config\u002Flaravels.php`\n'event_handlers' => [\n    'ServerStart' => [\\App\\Events\\ServerStartEvent::class], \u002F\u002F Trigger events in array order\n    'WorkerStart' => [\\App\\Events\\WorkerStartEvent::class],\n],\n```\n\n### Serverless\n\n#### Alibaba Cloud Function Compute\n> [Function Compute](https:\u002F\u002Fwww.alibabacloud.com\u002Fhelp\u002Fproduct\u002F50980.htm).\n\n1.Modify `bootstrap\u002Fapp.php` and set the storage directory. Because the project directory is read-only, the `\u002Ftmp` directory can only be read and written.\n\n```php\n$app->useStoragePath(env('APP_STORAGE_PATH', '\u002Ftmp\u002Fstorage'));\n```\n\n2.Create a shell script `laravels_bootstrap` and grant `executable permission`.\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\nset +e\n\n# Create storage-related directories\nmkdir -p \u002Ftmp\u002Fstorage\u002Fapp\u002Fpublic\nmkdir -p \u002Ftmp\u002Fstorage\u002Fframework\u002Fcache\nmkdir -p \u002Ftmp\u002Fstorage\u002Fframework\u002Fsessions\nmkdir -p \u002Ftmp\u002Fstorage\u002Fframework\u002Ftesting\nmkdir -p \u002Ftmp\u002Fstorage\u002Fframework\u002Fviews\nmkdir -p \u002Ftmp\u002Fstorage\u002Flogs\n\n# Set the environment variable APP_STORAGE_PATH, please make sure it's the same as APP_STORAGE_PATH in .env\nexport APP_STORAGE_PATH=\u002Ftmp\u002Fstorage\n\n# Start LaravelS\nphp bin\u002Flaravels start\n```\n\n3.Configure `template.xml`.\n\n```xml\nROSTemplateFormatVersion: '2015-09-01'\nTransform: 'Aliyun::Serverless-2018-04-03'\nResources:\n  laravel-s-demo:\n    Type: 'Aliyun::Serverless::Service'\n    Properties:\n      Description: 'LaravelS Demo for Serverless'\n    fc-laravel-s:\n      Type: 'Aliyun::Serverless::Function'\n      Properties:\n        Handler: laravels.handler\n        Runtime: custom\n        MemorySize: 512\n        Timeout: 30\n        CodeUri: .\u002F\n        InstanceConcurrency: 10\n        EnvironmentVariables:\n          BOOTSTRAP_FILE: laravels_bootstrap\n\n```\n\n## Important notices\n\n### Singleton Issue\n\n- Under FPM mode, singleton instances will be instantiated and recycled in every request, request start=>instantiate instance=>request end=>recycled instance.\n\n- Under Swoole Server, All singleton instances will be held in memory, different lifetime from FPM, request start=>instantiate instance=>request end=>do not recycle singleton instance. So need developer to maintain status of singleton instances in every request.\n\n- Common solutions:\n\n    1. Write a `XxxCleaner` class to clean up the singleton object state. This class implements the interface `Hhxsv5\\LaravelS\\Illuminate\\Cleaners\\CleanerInterface` and then registers it in `cleaners` of `laravels.php`.\n\n    2. `Reset` status of singleton instances by `Middleware`.\n\n    1. Re-register `ServiceProvider`, add `XxxServiceProvider` into `register_providers` of file `laravels.php`. So that reinitialize singleton instances in every request [Refer](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FSettings.md#register_providers).\n\n### Cleaners\n> [Configuration cleaners](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FSettings.md#cleaners).\n\n### Known issues\n> [Known issues](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FKnownIssues.md): a package of known issues and solutions.\n\n### Debugging method\n\n- Logging; if you want to output to the console, you can use `stderr`, Log::channel('stderr')->debug('debug message').\n\n- [Laravel Dump Server](https:\u002F\u002Fgithub.com\u002Fbeyondcode\u002Flaravel-dump-server)(Laravel 5.7 has been integrated by default).\n\n### Read request\nRead request by `Illuminate\\Http\\Request` Object, $_ENV is readable, $_SERVER is partially readable, `CANNOT USE` $_GET\u002F$_POST\u002F$_FILES\u002F$_COOKIE\u002F$_REQUEST\u002F$_SESSION\u002F$GLOBALS.\n\n```php\npublic function form(\\Illuminate\\Http\\Request $request)\n{\n    $name = $request->input('name');\n    $all = $request->all();\n    $sessionId = $request->cookie('sessionId');\n    $photo = $request->file('photo');\n    \u002F\u002F Call getContent() to get the raw POST body, instead of file_get_contents('php:\u002F\u002Finput')\n    $rawContent = $request->getContent();\n    \u002F\u002F...\n}\n```\n\n### Output response\nRespond by `Illuminate\\Http\\Response` Object, compatible with echo\u002Fvardump()\u002Fprint_r()，`CANNOT USE` functions dd()\u002Fexit()\u002Fdie()\u002Fheader()\u002Fsetcookie()\u002Fhttp_response_code().\n\n```php\npublic function json()\n{\n    return response()->json(['time' => time()])->header('header1', 'value1')->withCookie('c1', 'v1');\n}\n```\n\n### Persistent connection\n`Singleton connection` will be resident in memory, it is recommended to turn on `persistent connection` for better performance.\n1. Database connection, it `will` reconnect automatically `immediately` after disconnect.\n\n```php\n\u002F\u002F config\u002Fdatabase.php\n'connections' => [\n    'my_conn' => [\n        'driver'    => 'mysql',\n        'host'      => env('DB_MY_CONN_HOST', 'localhost'),\n        'port'      => env('DB_MY_CONN_PORT', 3306),\n        'database'  => env('DB_MY_CONN_DATABASE', 'forge'),\n        'username'  => env('DB_MY_CONN_USERNAME', 'forge'),\n        'password'  => env('DB_MY_CONN_PASSWORD', ''),\n        'charset'   => 'utf8mb4',\n        'collation' => 'utf8mb4_unicode_ci',\n        'prefix'    => '',\n        'strict'    => false,\n        'options'   => [\n            \u002F\u002F Enable persistent connection\n            \\PDO::ATTR_PERSISTENT => true,\n        ],\n    ],\n],\n```\n\n2. Redis connection, it `won't` reconnect automatically `immediately` after disconnect, and will throw an exception about lost connection, reconnect next time. You need to make sure that `SELECT DB` correctly before operating Redis every time.\n\n```php\n\u002F\u002F config\u002Fdatabase.php\n'redis' => [\n    'client' => env('REDIS_CLIENT', 'phpredis'), \u002F\u002F It is recommended to use phpredis for better performance.\n    'default' => [\n        'host'       => env('REDIS_HOST', 'localhost'),\n        'password'   => env('REDIS_PASSWORD', null),\n        'port'       => env('REDIS_PORT', 6379),\n        'database'   => 0,\n        'persistent' => true, \u002F\u002F Enable persistent connection\n    ],\n],\n```\n\n### About memory leaks\n\n- Avoid using global variables. If necessary, please clean or reset them manually.\n\n- Infinitely appending element into `static`\u002F`global` variable will lead to OOM(Out of Memory).\n\n    ```php\n    class Test\n    {\n        public static $array = [];\n        public static $string = '';\n    }\n\n    \u002F\u002F Controller\n    public function test(Request $req)\n    {\n        \u002F\u002F Out of Memory\n        Test::$array[] = $req->input('param1');\n        Test::$string .= $req->input('param2');\n    }\n    ```\n\n- Memory leak detection method\n\n    1. Modify `config\u002Flaravels.php`: `worker_num=1, max_request=1000000`, remember to change it back after test;\n\n    2. Add routing `\u002Fdebug-memory-leak` without `route middleware` to observe the memory changes of the `Worker` process;\n\n    ```php\n    Route::get('\u002Fdebug-memory-leak', function () {\n        global $previous;\n        $current = memory_get_usage();\n        $stats = [\n            'prev_mem' => $previous,\n            'curr_mem' => $current,\n            'diff_mem' => $current - $previous,\n        ];\n        $previous = $current;\n        return $stats;\n    });\n    ```\n\n    3. Start `LaravelS` and request `\u002Fdebug-memory-leak` until `diff_mem` is less than or equal to zero; if `diff_mem` is always greater than zero, it means that there may be a memory leak in `Global Middleware` or `Laravel Framework`;\n    \n    4. After completing `Step 3`, `alternately` request the business routes and `\u002Fdebug-memory-leak` (It is recommended to use `ab`\u002F`wrk` to make a large number of requests for business routes), the initial increase in memory is normal. After a large number of requests for the business routes, if `diff_mem` is always greater than zero and `curr_mem` continues to increase, there is a high probability of memory leak; If `curr_mem` always changes within a certain range and does not continue to increase, there is a low probability of memory leak.\n\n    5. If you still can't solve it, [max_request](https:\u002F\u002Fwww.swoole.co.uk\u002Fdocs\u002Fmodules\u002Fswoole-server\u002Fconfiguration#max_request) is the last guarantee.\n\n### Linux kernel parameter adjustment\n> [Linux kernel parameter adjustment](https:\u002F\u002Fwiki.swoole.com\u002F#\u002Fother\u002Fsysctl?id=%e5%86%85%e6%a0%b8%e5%8f%82%e6%95%b0%e8%b0%83%e6%95%b4)\n\n### Pressure test\n> [Pressure test](https:\u002F\u002Fwiki.swoole.com\u002Fwiki\u002Fpage\u002F62.html)\n\n## Alternatives\n\n- [swooletw\u002Flaravel-swoole](https:\u002F\u002Fgithub.com\u002Fswooletw\u002Flaravel-swoole)\n\n## Sponsor\n\n- [PayPal](https:\u002F\u002Fwww.paypal.me\u002Fhhxsv5)\n\n- [BTC](https:\u002F\u002Fwww.blockchain.com\u002Fbtc\u002Faddress\u002F367HnAzVTAEk8offesDhcsCQswnugsE54u)\n\n- [Gitee](https:\u002F\u002Fgitee.com\u002Fhhxsv5\u002Flaravel-s?donate=true)\n\n## Star History\n\n[![Star History Chart](https:\u002F\u002Fapi.star-history.com\u002Fsvg?repos=hhxsv5\u002Flaravel-s&type=date&legend=top-left)](https:\u002F\u002Fwww.star-history.com\u002F#hhxsv5\u002Flaravel-s&type=date&legend=top-left)\n\n## License\n\n[MIT](https:\u002F\u002Fgithub.com\u002Fhhxsv5\u002Flaravel-s\u002Fblob\u002FPHP-8.x\u002FLICENSE)\n","LaravelS 是一个开箱即用的 Laravel\u002FLumen 与 Swoole 之间的适配器。它通过利用 Swoole 的高性能特性，为基于 PHP 的 Web 应用提供异步处理、WebSocket 支持及定时任务等功能，从而显著提升应用性能和响应速度。此外，LaravelS 还支持多端口混合协议监听、协程操作以及自定义进程等高级功能。适用于需要高效处理大量并发请求、实现长连接或即时通讯服务的应用场景。",2,"2026-06-11 03:18:09","top_language"]