Phoenix Channels - Too easy to use?

I’ve been recently playing with Phoenix Channels. It’s what a lot of people call the bread and butter of Phoenix, it’s what makes Phoenix really powerful. I haven’t ran into a problem yet where I had to use them or that they were the fix solution I reached for. I’ve only written 2-3 small production elixir applications.

I’m currently playing with phoenix channels and using them instead of ajax to send data to the server when a user answers questions on a survey. It doesn’t seem like the best problem to be using them for, compared to maybe just ajax calls to a controller when a user answers the questions but it’s something I wanted to explore to solve a new feature request on the application I’m working on.

I’ve been going back and forth on when it makes sense to use channels and it seems like they make the most sense when:

  • Sending data bidirectionally fairly often ( like chat )
  • When you want to send data from the server to the client ( like notifications )

I’ll give another good example that a co-worker and I recently had a discussion about:

We work in the medical industry and it’s pretty common to have an auto logout feature for our applications. So when a user isn’t active, we log them out.

On an older rails application we have, that is done via a javascript timer on the frontend and a session timeout on the backend. So if a user is on the site and stops using it, they are logged out and redirected, also if they decided to leave the application their session will expire after a certain amount of time as well.

My co-worker thought it would be interesting to see if we could implement that auto logout functionality with phoenix channels, and how well that would work.

So basically when a user visits an authenticated part of our site, we would open a phoenix channel and set the timeout to say 15mins. On channel timeout, we would logout the user. We could also expire the session via a plug like we normally do. This seems to greatly simplify the javascript side and lets us define a logout time that is both used for the channel disconnect time as well as the session disconnect time. So we’re not managing both the frontend and backend with possibly different timers.

On one hand I don’t think this is a good solution, because though it works it seems odd to use a web socket just to timeout and log a user out. Especially because the server has a process just sitting around for this use. I do understand that phoenix is very performant, and this would scale probably well beyond our needs, but it just doesn’t seem like the right solution.

On the other hand, I also hate dealing with a ton of javascript and this might be a good trade off until we ever do get to a problem with scale.

Should I be worried with how I am currently playing with using them?

I also think a more general question is, Phoenix makes it so easy to hookup channels and use them that it seems to be used in ways that may not make sense. When in other development stacks it would be a pain to setup and we would often skip over them unless they really make sense.

So the bigger question is, because phoenix makes them easier to setup and use I wonder if we will see them used in places where we normally wouldn’t, and if that makes it more of a blurry line between when it’s a good idea to use them versus not.

Use a channel for all communication between your client & server, boom problem solved :wink:

1 Like

I had more discussion about this in the elixir slack as well:

https://elixir-lang.slack.com/archives/C03QQCV4H/p1533605128000132

If the user disconnects from the internet, does that mean they won’t be logged out?

I don’t think you really get a choice about handling this on the server side only.

They would be logged out, via the session timeout.

They can’t get new data, but their window will not be closed.

Wouldn’t the session timeout be relevant only if the user did something that made a new request?

I could be suggesting stricter requirements than you need. On the app I work on, we need to clear any data we have in memory or session storage in the browser when the user is logged out. In order to do that, we implement a timeout on the client side like you mentioned. We use JWT’s for session, but that expiring would only make us not able to make new requests.

I have some similar questions, without having run in to real world problems due to mostly tinkering and prototyping.

Is it problematic to connect to 10 channels for a SPA? 25? 100?

I have a use case where I’m trying to live update many different independent things and connecting to separate channels for each and handling them all in isolation feels good conceptually, but will my pipe get clogged so to speak?

Channels are an abstraction, each user has one socket connection and channels, no matter how many, use that socket.

That is if you only make requests once, but if your app makes a lot of them even if they are all directed from clients to server, channels can do that with almost no overhead whereas AJAX does normal HTTP requests - much more work. The difference in performance is IMO worth a process per user.

1 Like

I think this makes sense when you talk about the work being about opening up and tearing down TCP connections, but AJAX doesn’t require the server to have any long running process per client. Though I’m not concerned about any type of performance issues for a long time. It seems odd to have a process on the server sitting around per client than it does to just make an ajax call and let the server handle it in a stateless matter.

It’s not odd at all for BEAM–you’re biased by HTTP and other languages. That process sitting around will take up almost no resources, and in return you get to give up all the kludges that you’re used to doing in order to build a stateful app on top of stateless connections.

4 Likes

Well any request will create a process (or take it from the pool) just to handle this request.

If your page is a kind of application that does lots of stuff it’s arguably weirder to generate that many requests just to “serve” one user then to open a connection and use it to communicate with the server. For such use cases I consider channels to be a good match, even if the data flows from the client.

These are Erlang processes we are talking about, they are really tiny :slight_smile:

1 Like