Building Real-Time Systems: A Deep Dive into Laravel Reverb and ReactPHP
Overview of Real-Time Web Architecture
Traditional web applications operate on a request-response cycle. This model, while reliable, creates a significant lag when users need instant updates, such as chat messages or live status indicators. Developers often resort to short polling, where the client repeatedly hits the server to ask for new data. This is inefficient; it wastes server resources and creates a "stuttering" user experience.
Prerequisites
To follow this tutorial, you should be comfortable with:
- PHP 8.2+: Knowledge of modern PHP syntax and the Composerpackage manager.
- Laravel 11: Familiarity with the slimmed-down application skeleton and Artisan commands.
- JavaScript Basics: Understanding of how to handle events in the browser.
- Networking Concepts: Basic awareness of HTTP vs. WebSockets and UDP vs. TCP.
Key Libraries & Tools
- Laravel Reverb: The core websocket server package.
- Laravel Echo: The JavaScript library used to subscribe to channels and listen for events on the frontend.
- ReactPHP: A low-level library providing the asynchronous event loop that powers Reverb.
- Datagram Factory: A ReactPHP component for UDP communication (used for hardware integration).
- FFmpeg: A multimedia framework used here to process and stream video frames.
- Redis: Used as a Pub/Sub mechanism to scale Reverb horizontally across multiple servers.
Under the Hood: The Event Loop
Reverb doesn't use the typical synchronous PHP execution model. Instead, it relies on the while(true) loop that performs three critical tasks on every "tick":
- Future Ticks: It processes tasks deferred from previous iterations to avoid blocking the main thread.
- Timers: It executes scheduled tasks, such as pruning stale connections or heartbeats.
- I/O Streams: It monitors active sockets for incoming data.
By using non-blocking I/O, a single PHP process can keep thousands of connections "parked" in memory, only using CPU cycles when a connection actually sends or receives data. This is how Reverb achieves its massive scalability.
Code Walkthrough: Hardware Control via Websets
In advanced implementations, you can use Reverb's event loop to interface with hardware, like a drone, using
1. Initializing the Custom Server
To gain access to the raw loop, you might hand-roll a command instead of using the default reverb:start.
// Getting the underlying ReactPHP loop
$loop = \React\EventLoop\Loop::get();
// Starting the Reverb server with the loop
$server = ReverbServerFactory::make($loop, $config);
2. Communicating via UDP
Drones often require UDP for low-latency commands. We use the Datagram\Factory to create a client within the Reverb process.
$factory = new \React\Datagram\Factory($loop);
$factory->createClient('192.168.10.1:8889')->then(function ($socket) {
// Send an initialization command
$socket->send('command');
// Store the socket in a service for later use
app()->singleton(FlyService::class, fn() => new FlyService($socket));
});
3. Handling Client Whispers
To send commands from the UI (like "flip" or "move") without a full Laravel controller cycle, we can intercept Client Whispers. These are lightweight messages sent from one client to others that Reverb normally just passes through.
// Listening for Reverb's MessageReceived event
Event::listen(MessageReceived::class, function ($event) {
$message = $event->message;
if (str_starts_with($message, 'client-fly-')) {
$command = str_replace('client-fly-', '', $message);
// Resolve our UDP service and fire the command to the hardware
app(FlyService::class)->send($command);
}
});
Syntax Notes
- Non-blocking logic: Never use
sleep()or long-runningforeachloops inside the event loop. This stops the entire server. Use timers or chunking instead. - Singleton Pattern: When working with hardware sockets (UDP/TCP), bind the connection as a singleton in the Laravel container so it persists across different parts of the application.
- Client Whispers: These always start with the
client-prefix by convention inLaravel Echo.
Practical Examples
- Telemetry Dashboards: Streaming sensor data (battery, temperature, altitude) from IoT devices to a web UI in real-time.
- Video Streaming: Using FFmpeg to pipe video frames into a Reverb event, base64 encoding the image chunks, and rendering them onto a
<canvas>element on the frontend. - Live Collaborative Tools: Real-time cursor tracking or document editing where sub-100ms latency is required.
Tips & Gotchas
- Scaling with Redis: If you run multiple Reverb servers behind a load balancer, you must use the Redispublish/subscribe adapter. This ensures that an event received by Server A is broadcasted to clients connected to Server B.
- Avoid Deadlocks: Do not perform synchronous HTTP requests or database queries inside the
MessageReceivedlistener unless they are wrapped in an asynchronous wrapper. Doing so will block the event loop and potentially crash the websocket server. - Memory Usage: Since connections stay in memory, monitor your server's RAM. Laravel Pulseintegrates directly with Reverb to provide real-time monitoring of connection counts and message throughput.
