RoadRunner used to have its own WebSocket plugin for sending messages to clients, but we found it was too limited. We wanted to create a better solution for handling real-time data transmission and decided to stop developing our own plugin. Instead, we looked for one of the best open-source tools out there and found Centrifugo. We created a RoadRunner plugin called Centrifuge that integrates with Centrifugo server using GRPC API and it's a much more powerful and flexible option.
Here are some of the benefits of using Centrifugo:
With this integration, you can send events to WebSocket clients as well as handle events from the clients on the server.
Spiral has a full integration with the RoadRunner Centrifuge plugin, which facilitates communication between Spiral application and the Centrifugo WebSocket server.
Here are events that can be received on the server:
At first, you need to install the spiral/roadrunner-bridge package.
Once the package is installed, you can add the Spiral\RoadRunnerBridge\Bootloader\CentrifugoBootloader
to the list of
bootloaders:
public function defineBootloaders(): array
{
return [
// ...
\Spiral\RoadRunnerBridge\Bootloader\CentrifugoBootloader::class,
// ...
];
}
Read more about bootloaders in the Framework — Bootloaders section.
To configure the communication between RoadRunner and Centrifugo, you will need to modify the .rr.yaml
file.
rpc:
listen: tcp://0.0.0.0:6001
server:
command: "php app.php"
relay: pipes
centrifuge:
proxy_address: "tcp://0.0.0.0:10001"
grpc_api_address: "centrifugo:10000"
Where proxy_address
is the address of the RoadRunner Centrifuge plugin. It will be used by the Centrifugo server to
communicate with RoadRunner.
And grpc_api_address
is the address of the Centrifugo GRPC server. It will be used by the RoadRunner Centrifuge plugin
to communicate with the Centrifugo server.
See more
Read more about the configuration of the Centrifuge plugin here.
To complete the integration, you will need to configure the Centrifugo server by creating a config.json
file and
specifying the communication settings between Centrifugo and RoadRunner.
Here is an example config.json
file that shows how to configure the communication between servers
{
// ...
"allowed_origins": [
"*"
],
"publish": true,
"proxy_publish": true,
"proxy_subscribe": true,
"proxy_connect": true,
"allow_subscribe_for_client": true,
"grpc_api": true,
"grpc_api_address": "0.0.0.0",
"grpc_api_port": 10000,
"proxy_connect_endpoint": "grpc://127.0.0.1:10001",
"proxy_connect_timeout": "10s",
"proxy_publish_endpoint": "grpc://127.0.0.1:10001",
"proxy_publish_timeout": "10s",
"proxy_subscribe_endpoint": "grpc://127.0.0.1:10001",
"proxy_subscribe_timeout": "10s",
"proxy_refresh_endpoint": "grpc://127.0.0.1c:10001",
"proxy_refresh_timeout": "10s",
"proxy_rpc_endpoint": "grpc://127.0.0.1:10001",
"proxy_rpc_timeout": "10s"
}
See more
More information about Centrifugo server configuration you can read on the official documentation
In this configuration
proxy_connect_endpoint
- RoadRunner server address, which will handle the
new connection events
proxy_publish_endpoint
- RoadRunner server address, which will handle
the publish events
proxy_subscribe_endpoint
- RoadRunner server address, which will handle
the subscribe events
proxy_refresh_endpoint
- RoadRunner server address, which will handle
the refresh events
proxy_rpc_endpoint
- RoadRunner server address, which will handle
the rpc events
Centrifugo allows you to use multiple RoadRunner servers to handle different types of events. This can be useful in situations where you want to scale up the number of events that your application can handle or where you want to improve the reliability of the communication between Centrifugo and RoadRunner.
To use multiple, you will need to specify the addresses of the servers in the config.json
file. For example, you might
configure one RoadRunner server to handle connection events and another to handle RPC calls, as shown in the following
example configuration:
{
// ...
"proxy_connect_endpoint": "grpc://127.0.0.1:10001",
"proxy_connect_timeout": "10s",
"proxy_rpc_endpoint": "grpc://127.0.0.1:10002",
"proxy_rpc_timeout": "10s"
}
You can use this approach to distribute the workload among multiple RoadRunner servers, depending on your needs.
Note
Keep in mind that using multiple RoadRunner servers will require additional configuration and setup, and you will need to ensure that the servers are properly coordinated to ensure smooth operation. However, the benefits of increased scalability and reliability can be well worth the effort.
To use the Centrifuge in your application, you will need to create a centrifugo.php
file in
the app/config
directory. In this file, you can specify services that will handle incoming events from
the Centrifugo server, as well as any interceptors that should be applied to the events.
Here is an example of a centrifugo.php
config file that shows how to specify services and interceptors:
use RoadRunner\Centrifugo\Request\RequestType;
return [
'services' => [
RequestType::Connect->value => ConnectService::class,
RequestType::Subscribe->value => SubscribeService::class,
RequestType::Refresh->value => RefreshService::class,
RequestType::Publish->value => PublishService::class,
RequestType::RPC->value => RPCService::class,
],
'interceptors' => [
RequestType::Connect->value => [
Interceptor\AuthInterceptor::class,
],
RequestType::Subscribe->value => [
Interceptor\AuthInterceptor::class,
],
RequestType::RPC->value => [
Interceptor\AuthInterceptor::class,
],
'*' => [
Interceptor\TelemetryInterceptor::class,
],
],
];
See more
For more information on event handlers (services) and how to use them in a Spiral application, you can refer to the documentation section on Event Handlers. This page provides additional details and examples to help you get started with event handling.
You can use the official JavaScript SDK for Centrifugo to facilitate communication between the Centrifugo server and the client browser in your application. It provides a set of APIs that allow you to connect to the Centrifugo server, subscribe to channels, and receive messages in real-time.
Using the JavaScript SDK, you can establish a WebSocket connection between the client and the Centrifugo server, and all communication between RoadRunner and the client will be routed through the Centrifugo server. This means that you don't need to open any additional ports on your server to support real-time communication between the client and the server.
To enable WebSocket connections with Centrifugo server using Nginx proxy, you need to configure the proxy accordingly.
This can be done by including the following configuration in the Nginx configuration file:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8000;
server_name _;
# Centrifugo WebSocket endpoint
location /connection {
proxy_pass http://127.0.0.1:8000/connection;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
# RoadRunner HTTP endpoint
location / {
proxy_pass http://127.0.0.1:8080;
}
}
See more
More information about Nginx proxy configuration you can read on the official documentation.
There is a good example Demo ticket booking system application built on the Spiral, which is a high-performance PHP framework that follows the principles of microservices and allows developers to create reusable, independent, and easy-to-maintain components.
It demonstrates how to use RoadRunner's Centrifuge plugin to enable real-time communication between the Centrifugo server and the client browser.