7

I'm planning on writing a Rails app where multiple users are going to have updated information pushed to them using server-sent events with ActionController::Live and Puma. I've already written a test app and it seems to work very well. For what I'm doing, SSEs make more sense than WebSockets as most of the users are just 'listening' and SSEs are much simpler than setting up websockets-rails which also depends on Faye(in which case I'd just write my own code on top of Faye).

What I want to know is just how scalable are server-sent events in Rails? This is under the premise that I'll be using Puma, which creates a new thread for every user who is connected to the EventSource. Potentially, this app aims towards the possibility of having hundreds of thousands of users connected at once, but by Puma's default thread limit is 16. Is there any reason why I can't change the thread limit to 200,000?

Ten Bitcomb
  • 2,316
  • 1
  • 25
  • 39
  • 1
    Aren't SSEs still missing from MS IE? – Gene Aug 24 '14 at 00:53
  • I think the challenges you'll see with the Rails/Puma stack are the same as any stack. A thread/user sounds like overkill but I don't know enough about your use case to comment. Increasing the threads puma uses obviously increases cpu utilization and is limited by the number of CPUs. 16 is a good default. 200,000 is way way way too many threads. – adi-pradhan Aug 24 '14 at 01:33
  • @adi-pradhan totally agree with you. Python + gevent handle this problem quite well, curious about the best Ruby approach to this. – Martin Konecny Aug 24 '14 at 02:11
  • Gene - There is a polyfill for SSEs that works for IE. Adi - If that's true, then are the current examples and tutorials for SSEs in Rails impractical? They all suggest the use of Puma which is threaded; go over the maximum thread limit and new users cannot connect unless a thread is freed. In that case, 16 seems like quite a puny number, as this would mean that only 16 users can be connected to the event source or make other requests simultaneously. That's a very high price for concurrency. – Ten Bitcomb Aug 24 '14 at 08:00

3 Answers3

6

If Puma creates a new thread for each connection, don't use it. Not only do you plan for hundreds of thousands users at once but provided it's going to be a web application, users can have multiple instances open in multiple browser tabs. Even the SSE specification warns against the "multiple tabs" problem because browsers may have their own limits of the number of simultaneous connections to one host:

Clients that support HTTP's per-server connection limitation might run into trouble when opening multiple pages from a site if each page has an EventSource to the same domain. Authors can avoid this using the relatively complex mechanism of using unique domain names per connection, or by allowing the user to enable or disable the EventSource functionality on a per-page basis, or by sharing a single EventSource object using a shared worker.

Use an evented server where connections do not block. The above-mentioned gevent, something built on Node JS or something else in Ruby (which I don't know and thus can't recommend anything).

For other readers who land on this page and might get confused, Rich Peck's answer is wrong. Server-Sent Events don't rely on long polling, nor do they send requests every couple of seconds. They are long-lived HTTP connections without the need to reopen the connection after every event. There are no "constant requests to the server".

Community
  • 1
  • 1
Martin
  • 516
  • 4
  • 4
  • It might be worth looking into the [Falcon](https://socketry.github.io/falcon/) server for Ruby, which is an evented server – steve Nov 15 '22 at 20:35
1

About the Puma approach using one thread per client, given you have a limit of 16 threads per server, maybe you can think about horizontal scaling your servers? Like, if you deploy to amazon and set up Elastic Load Balancing + Auto Scaler, your infrastructure shoud be able to accept as many clients as needed. Or am I wrong ? And I guess the multiple tabs problem could be overpassed by forbidding multiple connections per client, displaying an appropriate error message if the user opens a new tab.

-4

I'm not sure about the threading issue, but from experience, I can give you some idea about SSE's


SSE's

The most important thing to consider is that SSE's depend on Javascript long polling, meaning it will continue to send requests to your server every few seconds, in an attempt to "listen" for updates

Check it when you set up an SSE eventlistener - it will send requests every couple of seconds to your server. The connection will not be perpetual

There's a great discussion about this here: What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?

--

The problem here, at least to me, is that if you're sending constant requests to your server, it's not only going to be inefficient, but also very constricted in terms of functionality

As with the pub/sub pattern, if you want to deliver "live" updates to your users, you'll want to firstly have some sort of authentication (which I believe SSE's don't provide), as well as ensuring you have particular "channels" for those users to receive updates for them

Having said that, there's a great post about creating a chat application with SSE's here:

enter image description here

I've only ever used SSE's for sending site-wide updates, for the simple fact that I'd prefer to have a single connection (websocket), which I can authenticate & populate with a user's specific data


Pusher

We use websockets wherever we can

The trick, though, is that you can use a third-party websock provider, like Pusher. I'm not affiliated with Pusher in any way; we have used them for a number of projects - EPIC service

Using Pusher, you'll be able to accept & deliver specific messages to the users on your site without having to set up your own websocket server. You just connect to Pusher's service with the same JS setup (eventlistener), which will only connect once to the Pusher service: enter image description here

You can then send updates to your users by just "pushing" to the Pusher API. We have set this up tentatively with an analytics app we are in the process of building out here


To answer your question, I don't know how scaleable SSE's are

I tend to take lead from the "big" internet companies (as a demonstration on how to do it "right"), and I've yet to see any of them favour SSE's over websockets. I may be wrong, but they all prefer websockets

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Thank you for the information you provided. Security isn't much of an issue for me since the information that is being streamed is supposed to be viewed by all users. I chose SSEs over WebSockets because of simplicity and because the number of extra connections(AJAX) is minimal in this case. So in reality, the only requests that would be occurring would be the initial eventsource connection from a client and a handful of AJAX requests every now and then. – Ten Bitcomb Aug 25 '14 at 00:31