Skip to content

Add Rails Action Cable comparison page#58

Open
irinanazarova wants to merge 10 commits into
masterfrom
compare-rails-actioncable
Open

Add Rails Action Cable comparison page#58
irinanazarova wants to merge 10 commits into
masterfrom
compare-rails-actioncable

Conversation

@irinanazarova

Copy link
Copy Markdown
Contributor

New /compare/rails-actioncable page: Action Cable vs Solid Cable vs AsyncCable vs AnyCable, the Rails counterpart to the existing /compare/nodejs-websocket page.

What it compares

Four Rails WebSocket adapters running the same Rails 8.1 app on identical Railway hardware, in one shared-tenant window:

Adapter Runtime Topology
Action Cable Puma + Redis in-process
Solid Cable Puma + database in-process
AsyncCable Falcon (fibers) in-process
AnyCable Go gateway + Rails RPC out-of-process

All four speak the Action Cable API, so channels and Turbo Streams are unchanged. The only thing that varies is what runs the WebSockets.

Findings (sharded load fleet)

  • Latency: AnyCable fastest at every scale (7 ms p50 at 5K vs 13 ms Action Cable, 20 ms AsyncCable, 74 ms Solid Cable)
  • Jitter delivery: AnyCable 99.9% vs ~78% for the three at-most-once in-process adapters (base actioncable-v1-json has no resume; AnyCable's actioncable-v1-ext-json replays per-stream history)
  • Deploy survival: AnyCable drops 0 connections on an app redeploy; the in-process adapters drop all 5,000 and reconnect ~96% in ~8 s
  • Capacity: all four hold 10K subscribers at 100% delivery; pushed to failure on a 32 GB box, the Puma adapters wall at ~52K (file-descriptor ceiling), Falcon at ~97K (memory), and AnyCable held 600K with zero failures

Implementation

  • Reuses the global compare.scss / compare-spine.scss system and the document skeleton from the nodejs-websocket page
  • Inline architecture SVG (in-process vs out-of-process gateway), code-tab widget, four data tables, feature matrix, FAQ accordion
  • FAQPage + TechArticle JSON-LD
  • All numbers reproducible from the open-source bench repo; raw results committed there

Benchmark methodology and raw data live in the separate bench repo (nodejs-websocket-bench).

New /compare/rails-actioncable page comparing four Rails WebSocket
adapters on identical hardware: Action Cable (Puma+Redis), Solid Cable
(Puma+DB), AsyncCable (Falcon), and AnyCable (out-of-process Go gateway).

All four speak the Action Cable API, so channels and Turbo Streams are
unchanged. Measured across four rubrics with a sharded load fleet:

- Latency: AnyCable fastest at every scale (7ms p50 at 5K)
- Jitter delivery: AnyCable 99.9% vs ~78% for the at-most-once in-process trio
- Deploy survival: AnyCable 0 dropped vs all-drop for in-process adapters
- Capacity: all hold 10K at 100%; pushed to failure, Puma adapters wall
  ~52K (fd limit), Falcon ~97K (memory), AnyCable held 600K with 0 failures

Reuses the compare.scss / compare-spine.scss system and the document
skeleton from the nodejs-websocket page. Includes FAQPage + TechArticle
JSON-LD.
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Applied feedback from reviews channeling DHH, David Cramer, Matt Biilmann,
Guillermo Rauch, a scaling-Rails-shop CTO, and LLM/answer-engine retrieval:

- Lead the callout with the architectural choice (in-process vs separate
  Go gateway) and the undeniable wins (jitter, deploy), not latency; state
  the two precise causes (process for deploys/capacity, protocol for delivery)
- Add a "Should you switch?" decision box with triggers + one-line rollback
- Add a "How it was measured" methodology disclosure (box, driver locality,
  runtimes, per-cell counts, single-pass honesty, raw-results link)
- De-FUD "What this breaks": acknowledge the refetch-on-reconnect workaround,
  drop "nobody can recover"; label the jitter run as a deliberate stress test;
  soften deploy "stranded" to "still reconnecting when we stopped watching"
- Present 600K as a floor (ran out of load fleet, not server); drop the
  ~700K extrapolation
- Note latency is where the four sit closest (7 vs 13 ms barely felt)
- Hero card labels: outcome phrases instead of questions; deploy values
  carry the count ("all 5,000"); jitter p99 column made non-numeric (n/a)
- New FAQs: which adapter to choose, what is AnyCable, Action Cable
  connection limit, do I need Go, does 99.9% need a client swap
- Sharpen the architecture thesis (subtitle, section heading, figcaption)
- Add keywords + a machine-readable Dataset JSON-LD; mirror new FAQs in
  FAQPage JSON-LD
Report how long the in-process adapters stay dropped before reconnecting
(~7.5 to 8 s, ~96% recovered) instead of only the reconnect percentage.
Reorder the deploy table to Dropped / Down for / Reconnected, redefine the
footnote, and add downtime to the Dataset JSON-LD.
New hand-authored /compare landing page that hosts every comparison,
reusing the existing compare-hub-* CSS component set (added earlier,
previously unused). Hero, then three stack cards (Node.js and Rails
live, Laravel/PaaS coming soon), a three-topology landscape map with
AnyCable tagged "You are here", and a CTA. Adds CollectionPage +
ItemList JSON-LD.

Point the footer "Comparisons" link at /compare instead of the
Node.js page now that there is a hub.
Add the /compare hub and the new Rails benchmark page to llms.txt and
llms-full.txt: a benchmark-backed "when to use AnyCable instead of
Action Cable / Solid Cable / AsyncCable" section, a Rails article entry
and (in the full file) a complete Rails methodology + results section
with latency, jitter, capacity, and deploy tables. Link the hub and the
Rails page in both Links sections.
- Capacity: the 1M idle figures were stale (OSS 993,994 / Pro 999,954).
  Correct to the published compare-page numbers: OSS 821,877 @ 28.3 GB
  (~34 KB/conn), Pro 822,037 @ 14.8 GB (~18 KB/conn), uWS 1,018,366 @
  5.45 GB. Fixes an internal contradiction where llms.txt disagreed with
  itself. Recompute Pro efficiency (~1.9x, was 1.7x).
- Avalanche: replace the single-scale Socket.io table with the page's
  scale sweep (5K-25K), adding the uWS data point.
- Pricing: Managed is free for early users (up to 2,000 connections),
  not "$29/month" (no such price on the site). Pro is unlimited
  instances and connections.
- Action Cable "~500 connections" claim corrected to the benchmarked
  in-process ceiling (~52,000) and reframed around deploy drops and
  at-most-once.
- Customer figures aligned to the site / web sources: CompanyCam
  $452M raised / $2B valuation (was $30M+), Qualified acquired by
  Salesforce (was $95M raised), Circle $33M, Fullscript $240M+. Drop
  Jane's "$100M+ raised" (that figure is revenue/secondary, not capital).
Match the gem's own naming: the README heading and Ruby constant are
Async::Cable (the gem package stays async-cable). Update the Rails
comparison page (title, hero, tables, prose, FAQ, JSON-LD) and the
Rails sections of both llms files.
Surface per-connection idle RAM for all four adapters in the "How far
does it scale?" table (~45 KB Action Cable, ~50 KB Solid Cable, ~290 KB
Async::Cable, ~47 KB AnyCable), computed as peak RSS / connections held.
Flag Falcon's ~290 KB as the outlier that makes it memory-bound. Move
the figure out of the prose footnote to avoid duplication.
…ped"

"All 5,000 dropped" is a given for any in-process server, so it earned a
test we didn't need. Drop that column and lead with the metrics that
actually inform: blackout duration (Down for) and the share that
reconnects within the window (Recovered, with the residual still-out
count). Every in-process adapter still dropped all 5,000; that fact moves
to the footnote as context. Reframe the hero card to downtime (7.5-8 s vs
0 s) and update the headline and Dataset JSON-LD to match.
The "Down for" figure is recoveryTimeMs from the avalanche runner,
defined as time from redeploy until 95% of clients are back. Say so
explicitly in the column header, headline, footnote, hero card, and
Dataset JSON-LD instead of the vaguer "blackout before reconnect".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant