Skip to content

Instantly share code, notes, and snippets.

@tranphuoctien
Last active February 15, 2022 05:24
Show Gist options
  • Save tranphuoctien/62e70b0f5b1c506b90537f43ba8b417a to your computer and use it in GitHub Desktop.
Save tranphuoctien/62e70b0f5b1c506b90537f43ba8b417a to your computer and use it in GitHub Desktop.
How to scale Ratchet php using redis
<?php
/*
* Author: https://blog.madbob.org/scaling-websockets-in-php/
*/
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\Socket\Server as Reactor;
use Clue\React\Redis\Factory;
use Clue\React\Redis\Client;
/*
This is the interface to Redis
*/
class LivePusher
{
private $sender_redis = null;
private $subscriber_redis = null;
private $server = null;
public function __construct($loop)
{
$factory = new Factory($loop);
/*
Note: cannot use the same Redis client for both subscribe and publish
*/
$this->sender_redis = $factory->createLazyClient($REDIS_HOST);
$this->subscriber_redis = $factory->createLazyClient($REDIS_HOST);
$this->subscriber_redis->subscribe('live_signalling');
}
public function setServer($server)
{
$this->server = $server;
$this->subscriber_redis->on('message', function ($channel, $payload) use ($server) {
/*
Deliver here the message to the proper $server->clients
*/
});
}
public function publish($msg)
{
$this->sender_redis->publish('live_signalling', $msg);
}
}
/*
This is the interface to the websocket
*/
class LiveServer implements MessageComponentInterface
{
public $clients;
private $pusher;
public function __construct()
{
$this->clients = [];
}
public function setPusher($pusher)
{
$this->pusher = $pusher;
}
private function closeConnection($connection)
{
/*
Remove the connection from $this->clients
*/
}
public function onOpen(ConnectionInterface $conn)
{
/*
Save in $this->clients the informations about the connections, organizing them by user
*/
}
public function onMessage(ConnectionInterface $from, $data)
{
$this->pusher->publish($msg);
}
public function onClose(ConnectionInterface $conn)
{
$this->closeConnection($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
$this->closeConnection($conn);
$conn->close();
}
}
/*
The trick here is share the same ReactPHP loop for both the
asyncronous Redis client and the websocket server, to run them in
parallel on the same instance
*/
$loop = \React\EventLoop\Factory::create();
$server = new LiveServer();
$socket = new Reactor('0.0.0.0:9090', $loop);
$ioserver = new IoServer(new HttpServer(new WsServer($server)), $socket, $loop);
$pusher = new LivePusher($loop);
$pusher->setServer($server);
$server->setPusher($pusher);
$loop->run();
@tranphuoctien
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment