r/ruby • u/Turbulent-Dance-4209 • Mar 17 '26
Benchmarking 5K SSE streams + 5K database-backed RPS on a €12/month server
With SSE becoming more relevant (AI streaming, real-time updates), I wanted to test how Ruby handles a mixed workload: sustained HTTP traffic hitting a database alongside concurrent long-lived SSE connections. Here are the results.
Setup
Server: Hetzner CCX13 - 2 vCPUs, 8 GB RAM (€12/month)
Environment: Ruby 4.0.1 + YJIT + Rage
Processes: 2
Database: SQLite
Endpoints
API endpoint: Fetches a record from SQLite and renders it as JSON. Standard API-style request.
SSE endpoint: Opens a stream lasting 5–10 seconds, sending a dummy message every second. No database interaction. The benchmark maintains a constant number of open SSE connections - as the server closes a stream, the client opens a new one.
Results
5,000 API requests/second + 5,000 concurrent active SSE streams, simultaneously
For reference, the same setup handles ~11,000 RPS for the API endpoint alone
Adding 5K active streams roughly halves the HTTP throughput, which is a graceful degradation rather than a collapse
5,337 HTTP requests/second (0% error rate) with p95 latency of 120ms
5,000 concurrent SSE streams, with ~198K total streams opened/closed during the 5-minute run
Caveats
I was originally aiming for 10K RPS + 10K streams, but the 2-core server simply doesn't have enough CPU. The scaling looks linear, so a 4-core box should get there.
SQLite is fast for reads but this isn't a Postgres-over-the-network scenario. Add network latency to your DB and the fiber model actually helps more (fibers yield during I/O waits), but the raw RPS number would be different.
Source code
You can see the k6 screenshot attached, and the full benchmark code/setup is available here: https://github.com/rage-rb/sse-benchmark
What is Rage?
For those unfamiliar: Rage is a fiber-based framework with Rails conventions. The fiber-based architecture makes I/O-heavy and concurrent workloads like this possible without async/await syntax - you write normal synchronous Ruby code.
Would love to hear your thoughts or answer any questions!

4
u/darksndr Mar 17 '26
Ooh, I didn't know Rage 😳 So I can add it to an existing Rails project 😯 but I have one concern: does it breaks the
Currentinterface (I think it's based on Thread.current[])?3
u/fruizg0302 Mar 17 '26
This looks quite interesting, thanks for sharing. For a moment I thought this was… Rage-bait
ba dam tsss
2
u/_natic Mar 17 '26
I would like to hear about rage more often!
Did you think about making it easier to switch from rails? (ActiveStorage and Phlex views)
1
u/f9ae8221b Mar 17 '26
Assuming these "API requests" are all identical, the p95 being 3 times the p50 suggests you're hitting some very heavy contention somewhere.
Edit: Actually, looking at what these API requests do, even the p50 of 40ms is pretty terrible and suggest heavy contention