Should the ActionCable server be extracted from ActionCable?

This issue is a discussion, not a bug report.

I’m opening the question for discussion because:

  1. With AnyCable in mind and in with the new Websocket Rack specification proposal, separation of concerns might be beneficial (similar to the way the web server was extracted).

  2. The Websocket-Shootout benchmark had some very troubling results. I emailed Jack about it and he pointed out that ActionCable was crashing as well as slow.

I believe that similar to the way the HTTP server was extracted from earlier Rails versions, the extraction of the Websocket server (the event loop currently based on nio4r) with a clear API, could both make maintenance easier and allow for performance improvements (i.e., by utilizing a platform specific optimized server).

What is your opinion?

Should the ActionCable server be extracted from ActionCable?

1 Like

Hey,

AnyCable looks lovely and it’ll be interesting to follow the new Rack specification. But Action Cable should work out-of-the-box with no additional servers or setups required beyond Puma. If there are options available that fulfill that criteria and are drop-in replacements, awesome, let’s look at that. Also happy to accommodate whatever AnyCable might need, but haven’t seen any requests.

So let’s wait to see some real approaches that need the existing server extracted before we venture down that path.

Whatever benchmarks that were done against 5.0.0 should take another go against 5.0.1. Tons of Action Cable fixes for both performance and stability. But regardless of what that changes, the overall story will remain the same. Ruby is never going to win any Hello World shoot-out against C++ or microframeworks. That’s as true for a regular 200 OK request as it is for a websockets connection. That doesn’t mean we shouldn’t seek to improve performance, and options like AnyCable might do so dramatically, just that we should have realistic expectations of where things go.

For Basecamp 3, which Action Cable was developed for and extracted from, our main issue has been less raw websocket performance and more just doing the work that is needed across that wire. Kinda like how doing 2,000 req/sec on a “Hello World” 200 OK is a bit irrelevant compared to building a real app. It’s extremely unlikely that the overhead of your underlying server is going to be the bottleneck. It’s more likely to be your application logic.

All depends on your use case, of course. And happy to see others push the performance of Action Cable further. As-is, it’s plenty good enough to run a major app like Basecamp 3.

1 Like

Hey, everyone!

  1. Action Cable built-in server is a great feature: “out-of-the-box” == “developer happiness”. That’s why we use Rails, don’t we?

That’s why I’m trying (as the author of AnyCable) to develop a transparent replacement for Action Cable server, only for production use, especially high-load.

So, I don’t think we should extract the Action Cable server from the framework.

But, as for me, we should think about decoupling application logic from low-level logic. There are some places in the codebase, where we mix application level logic with socket level logic – the Connection class, for example. It would be great to extract its public API (that we use in ApplicationCable::Connection).

Another example is the explicit usage of the server’s event loop in channels.

That’s why I have to patch these classes in AnyCable. But it would be better to avoid monkey-patching in favor of adapter-like implementation.

Btw, I’ve received a lot of requests to support AnyCable for non-Rails applications (yep, sounds a little bit strange) and I’m going to implement smth like Action Cable Lite – no Rails, no server, just application logic (channels, streams). Maybe, that could be a starting point to refactor the Action Cable.

  1. I’ve repeated WebSocket Shootout for many times, but I haven’t seen Action Cable crashing. It eats a lot of memory; it can be slow for broadcasting (when more than 1k connections per stream).

But it works.

Hey,

AnyCable looks lovely and it’ll be interesting to follow the new Rack specification. But Action Cable should work out-of-the-box with no additional servers or setups required beyond Puma. If there are options available that fulfill that criteria and are drop-in replacements, awesome, let’s look at that. Also happy to accommodate whatever AnyCable might need, but haven’t seen any requests.

Btw, there is an issue (https://github.com/rails/rails/issues/26999) with some proposals.

The most problematic feature (from the AnyCable point of view or other adapters, if any) – custom streaming callbacks. I’d like them to be deprecated)

Why? First, because they affect performance: straightforward broadcasting is much more efficient (=faster). And, secondly, IMO, it breaks the concept of broadcasting itself – we’re not simply re-transmitting messages to all clients, but we can do anything in the middle, different clients may receive different messages – should we have used different streams instead?

Do you use custom callbacks in Basecamp?

1 Like

I’d welcome refactorings to tease out the socket dynamics from the higher level bits. So do submit a PR on that. I’ve replied on the other PR re: callbacks. Thanks for working on this!

1 Like