[Feature Proposal] Add Action Cable support for EventSource and Server-sent Events

ActionCable provides applications with an alternative mechanism to bespoke HTTP-based polling. At its core, it depends on WebSockets to provide bi-directional communication: push and pull from both the client and server side. On the server-side, there is a Redis- or Postgres-backed broadcaster.

Server-sent events cover a lot of the same ground. They rely on a slightly different connection mechanism, but are also an alternative to bespoke HTTP-based polling. On the client side, they construct EventSource instances. Action Dispatch already supports the server-side mechanisms via its ActionController::Live module and the ActionController::Live::SSE class.

On the client-side, WebSocket and EventSource interfaces share open, message, and error events (EventSource listeners, WebSocket listeners) and are capable of reading arbitrarily shaped messages.

There are some trade-offs to consider. Server-sent event data only flows in one direction: from server to client. This means that any ActionCable connection that sends data from the client would still require the WebSocket variation.

In my personal experience writing applications that layer abstractions on top of Action Cable (like Turbo’s Stream broadcasting), transmitting data from the client to the server is handled by HTTP based form submissions, fetch, or XMLHttpRequests, and rarely relies on WebSockets’ client-to-server capabilities.

From an Operations perspective, EventSource and Server-sent Events are backed by HTTP connections and don’t require the same tools and technologies to maintain as WebSockets. In recent years, Heroku has become more flexible when handling polling and streaming responses.

In practice, re-structuring the Action Cable codebase to support two styles of adapter could be a sizable undertaking. Having recognized that, the asynchrony and Redis- or Postgres-backed could probably remain unchanged.

Is this something worth attempting?

If WebSockets are considered too integral to Action Cable, would it be worth making the broadcasting stack more re-usable so that applications could use it outside of Action Cable (like in an ActionController::Live controller of their own)?