LaravelS 是 Laravel/Lumen 和 Swoole 之间的即用适配器。
Watch this repository to get the latest updates.Built-in Http/WebSocket server
Memory resident
Gracefully reload
Support Laravel/Lumen both, good compatibility
Simple & Out of the box
>=8.2 Enable extension intl
Swoole
>=5.0
Laravel/Lumen
>=10
1.Require package via Composer(packagist).
# PHP >=8.2
composer require "hhxsv5/laravel-s:~3.8.0"
# PHP >=5.5.9,<=7.4.33
# composer require "hhxsv5/laravel-s:~3.7.0"
# Make sure that your composer.lock file is under the VCS
2.Register service provider(pick one of two).
Laravel: in config/app.php file, Laravel 5.5+ supports package discovery automatically, you should skip this step
'providers' => [
//...
Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class,
],
Lumen: in bootstrap/app.php file
$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);
3.Publish configuration and binaries.
After upgrading LaravelS, you need to republish; click here to see the change notes of each version.
php artisan laravels publish
# Configuration: config/laravels.php
# Binary: bin/laravels bin/fswatch bin/inotify
4.Change config/laravels.php: listen_ip, listen_port, refer Settings.
5.Performance tuning
Number of Workers: 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/(1s/1ms) = 100, so incremental pressure testing is needed to calculate the best worker_num.
Please read the notices carefully before running, Important notices(IMPORTANT).
php bin/laravels {start|stop|restart|reload|info|help}.onStop of Custom process
restart
Restart LaravelS: Stop gracefully before starting; The service is unavailable until startup is complete
reload
Reload all Task/Worker/Timer processes which contain your business codes, and trigger the method onReload of Custom process, CANNOT reload Master/Manger processes. After modifying config/laravels.php, you only have to call restart to restart
info
Display component version information
help
Display help information
start and restart.swoole.daemonize setting in laravels.php
-e|--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+
-i|--ignore
Ignore checking PID file of Master process
-x|--x-version
The version(branch) of the current project, stored in $_ENV/$_SERVER, access via $_ENV['X_VERSION'] $_SERVER['X_VERSION'] $request->server->get('X_VERSION')
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.runtime configuration file
storage/laravels.pid
PID file of Master process
storage/laravels-timer-process.pid
PID file of the Timer process
storage/laravels-custom-processes.pid
PID file of all custom processes
It is recommended to supervise the main process through Supervisord, the premise is without option
-dand to setswoole.daemonizetofalse.
[program:laravel-s-test]
directory=/var/www/laravel-s-test
command=/usr/local/bin/php bin/laravels start -i
numprocs=1
autostart=true
autorestart=true
startretries=3
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
Demo.
…
…
The Listening address of WebSocket Sever is the same as Http Server.
1.Create WebSocket Handler class, and implement interface WebSocketHandlerInterface.The instant is automatically instantiated when start, you do not need to manually create it.
…
2.Modify config/laravels.php.
// ...
'websocket' => [
'enable' => true, // Note: set enable to true
'handler' => \App\Services\WebSocketService::class,
],
'swoole' => [
//...
// Must set dispatch_mode in (2, 4, 5), see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
'dispatch_mode' => 2,
//...
],
// ...
3.Use SwooleTable to bind FD & UserId, optional, Swoole Table Demo. Also you can use the other global storage services, like Redis/Memcached/MySQL, but be careful that FD will be possible conflicting between multiple Swoole Servers.
4.Cooperate with Nginx (Recommended)
Refer WebSocket Proxy
…
5.Heartbeat setting
Heartbeat setting of Swoole
// config/laravels.php
'swoole' => [
//...
// 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.
'heartbeat_idle_time' => 600,
'heartbeat_check_interval' => 60,
//...
],
Proxy read timeout of Nginx
# Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds
proxy_read_timeout 60s;
6.Push data in controller
namespace App\Http\Controllers;
class TestController extends Controller
{
public function push()
{
$fd = 1; // Find fd by userId from a map [userId=>fd].
/**@var \Swoole\WebSocket\Server $swoole */
$swoole = app('swoole');
$success = $swoole->push($fd, 'Push data to fd#1 in Controller');
var_dump($success);
}
}
Usually, you can reset/destroy some
global/staticvariables, or change the currentRequest/Responseobject.
laravels.received_request After LaravelS parsed Swoole\Http\Request to Illuminate\Http\Request, before Laravel's Kernel handles this request.
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot`
// If no variable $events, you can also call Facade \Event::listen().
$events->listen('laravels.received_request', function (\Illuminate\Http\Request $req, $app) {
$req->query->set('get_key', 'hhxsv5');// Change query of request
$req->request->set('post_key', 'hhxsv5'); // Change post of request
});
laravels.generated_response After Laravel's Kernel handled the request, before LaravelS parses Illuminate\Http\Response to Swoole\Http\Response.
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot`
// If no variable $events, you can also call Facade \Event::listen().
$events->listen('laravels.generated_response', function (\Illuminate\Http\Request $req, \Symfony\Component\HttpFoundation\Response $rsp, $app) {
$rsp->headers->set('header-key', 'hhxsv5');// Change header of response
});
This feature depends on
AsyncTaskofSwoole, your need to setswoole.task_worker_numinconfig/laravels.phpfirstly. The performance of asynchronous event processing is influenced by number of Swoole task process, you need to set task_worker_num appropriately.
1.Create event class.
use Hhxsv5\LaravelS\Swoole\Task\Event;
class TestEvent extends Event
{
protected $listeners = [
// Listener list
TestListener1::class,
// TestListener2::class,
];
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function getData()
{
return
PHP Fatal error: Uncaught TypeError: Hhxsv5\LaravelS\LaravelS::convertRequest(): Argument #1 ($laravel) must be of type Hhxsv5\LaravelS\Illuminate\Laravel, null given
tcp server problem [ dispatch_mode 2 ] ...
PHP Fatal error: Uncaught ErrorException: Swoole\Server::start(): Swoole\WebSocket\Server->onClose handler error
Cannot run external program inside coroutine, if custom SIGHCLD handler was established
$request->user()在生产过程中获取值为null。
Problem with ZiggyCleaner (yes,again)
Response time increases possible memory leaks
dcat-admin 2.x 在不同页面来回切换,语言文件失效 [laravels-3.7.35]
Telescope 请求跟踪问题
系统偶发报connect() to unix:/dev/shm/live-server.sock failed