WebSockets or SSE with Phoenix Channels (and feasability of adding SSE)

Hi there!

I’m creating an app where I want to push (game score) updates to my clients, with clients participating in different games. There is no need for bidirectional traffic, the clients will only rarely push updates and the updates do not need to be real time so they can HTTP POST just fine. Updates will be irregular, only several times per hour, and it won’t really matter if there’s a delay in them.

I’ve been looking, naturally, at Phoenix Channels to achieve this outcome. WebSockets seem like an obvious way to go here, but since I don’t need the bidirectional traffic that they offer I’m wondering if there is an alternative solution and if there is a benefit in NOT using websockets.

I think server-sent events (SSE) is a perfect fit for my use case, but since Phoenix Channels don’t support them out of the box, I would have to build it myself as an alternative transport mechanism, which doesn’t seem trivial when looking at the current longpoll implementation. Which seems like development overkill, with easy WebSockets beckoning enticingly. I’ve come accross this project, but it doesn’t tie into channels as far as I can see, only allowing pushing to all clients, which is not what I’m looking for.

And then there is long polling, which I don’t really want to do because polling.

Is this really a sensible thing to worry about? Will (for example) the memory footprint of WebSockets actually exceed SSE’s, which will also need to be tied to their own process-per-client? If using SSE or long polling will allow me to serve twice (or more) the amount of concurrent users, than perhaps its worth doing, otherwise maybe I should just use sockets. Any thoughts? Experience with SSE?

You might be waiting for Liveview…

or use Drab

Thanks for the suggestion, but I actually quite like developing JS :slight_smile: so I’m developing a pure JSON API in Elixir, with a VueJS SPA in front of it.

I also prefer to separate frontend… And I use websocket as it is very easy to use from JS.

At the low level, there’s not much difference between long polling and SSEs. In order for SSE to work, there has to be a connection established between the server and a client, and the client is always the one initiating it.

If your primary goal is doing as little network communication as possible, I’d suggest having your clients periodically send a request to the server and getting the score back in response.

Hm the primary thing I’m worried about is not so much network traffic as it is increasing the server’s memory usage unnecessarily just to push a score update every now and then, by maintaining socket processes for every client. I wonder if SSE is more efficient. I suppose short polling might work as well in this case, especially when I cache the response, otherwise the database will be hit every time. Pushing seems better to me though, because the updates can be irregularly timed so a lot of requests will be wasted.

It is a fact that if you want to be able to push irregular updates to a client, you have to have a persistent connection established between it and the server. I don’t think it matters which particular API is used for this unless have 10s or 100s of thousands of clients.

@jsm I’m curious why you want to keep the Channels abstraction if only pushing updates one way.

We use ServerSentEvents in production in several services.

A nice interface for streaming was one of the triggers I had for building Raxx. Here is an example that pushes updates over SSE. https://github.com/CrowdHailer/watercooler/blob/master/lib/watercooler/www/listen.ex

However even in the services we are still using Phoenix we have not used the channel’s abstraction to send updates but instead use Plug.Conn.chunk https://hexdocs.pm/plug/Plug.Conn.html#chunk/2

1 Like

Hi, I saw your project when I posted the question :slight_smile: Correct me if I’m wrong, but I was under the impression that your use of SSE does not allow me to subscribe users only to certain topics (in my case, game instances) and that’s why I thought I would need Channels - or hook into PubSub myself.

Certainly that is the case, SSE is just a solution for sending messages to the client.
You will need your own solution for managing what needs to be sent. There are several ways to do this, and certainly if the subscription model looks a lot like channels then that might still be the best choice.

We do this for supporting GraphQL subscriptions via SSE. The HTTP request does a phoenix pubsub subscribe just like a websocket connection would, but then when it gets messages it pushes those out via SSE instead of via the websocket connection.

1 Like

Is “we” absinthe or the place you work at @benwilson512? I couldn’t find any reference to SSE in absinthe but maybe I didn’t look hard enough. This sounds really interesting for mobile subscriptions, I’d love to hear more about it.

Absinthe: https://hexdocs.pm/absinthe_plug/Absinthe.Plug.html#subscribe/3

It could use some docs though.