Engineering Note
Our Rails app handled 5,000 concurrent users easily. Adding real-time updates changed everything.
We introduced ActionCable for live notifications and status updates.
The feature worked perfectly in testing.
Production told a different story.
As adoption grew, we noticed:
* Memory usage increasing steadily
* WebSocket connections staying open for hours
* Background jobs competing with real-time broadcasts
* Response times becoming inconsistent during peak traffic
The surprising part?
The database wasn't the bottleneck.
Persistent connections were.
Instead of adding more application servers, we changed the architecture:
* Moved heavy work to Sidekiq before broadcasting
* Broadcast only essential updates
* Reduced unnecessary WebSocket subscriptions
* Monitored connection count alongside CPU and memory
The impact was immediate:
* Memory usage stabilised
* Fewer connection drops during peak traffic
* More consistent real-time performance
Important learning:
Real-time features are easy to build.
Running them reliably at scale is where the engineering starts.
Every open WebSocket is a long-lived production resource.
Treat it that way.
The feature worked perfectly in testing.
Production told a different story.
As adoption grew, we noticed:
* Memory usage increasing steadily
* WebSocket connections staying open for hours
* Background jobs competing with real-time broadcasts
* Response times becoming inconsistent during peak traffic
The surprising part?
The database wasn't the bottleneck.
Persistent connections were.
Instead of adding more application servers, we changed the architecture:
* Moved heavy work to Sidekiq before broadcasting
* Broadcast only essential updates
* Reduced unnecessary WebSocket subscriptions
* Monitored connection count alongside CPU and memory
The impact was immediate:
* Memory usage stabilised
* Fewer connection drops during peak traffic
* More consistent real-time performance
Important learning:
Real-time features are easy to build.
Running them reliably at scale is where the engineering starts.
Every open WebSocket is a long-lived production resource.
Treat it that way.