How to send user specific data on Group().send() on Channels?

209 views
Skip to first unread message

Utku Gültopu

unread,
Jan 2, 2017, 4:21:30 PM1/2/17
to Django users
In my application, I need run a piece of code (let's call it prepare_and_send_data(user)) for every online user, every N minutes. That piece of code will do a calculation using the data that belongs to the user, and send the results over a WebSocket connection.

Initially, I thought that Group('online-users').send({'data': 'data'}) sends the data to the websocket.send channel. Hence, I thought that if I write a consumer for the websocket.send channel, I can do my user specific calculations in the consumer for the websocket.send channel. Hence, calling Group('online-users').send({'data': 'data'}) every N minutes would have been enough to get the application going. Explaining with code:

@channel_session_user_from_http
def websocket_connect(message):
    Group('online-users').add(message.reply_channel)

@channel_session_user
def websocket_disconnect(message):
    Group('online-users').discard(message.reply_channel)

@channel_session_user
def websocket_send(message):
    # Do calculations here, using message.user and send it.

# Call Group('online-users').send({'data': 'data'}) every N minutes, which (I thought) will send the data to websocket.send # channel, hence the consumer for websocket.send channel will handle preparing the user specific data accordingly.


However, Group('online-users').send({'data': 'data'}) does not send the data to websocket.send channel. It sends the data directly over the WebSocket.

How should I handle this? It is possible to use a handler for Group('online-users').send({'data': 'data'})? AFAICT, using a Group to hold the online users is the best option, per the documentation. For this reason, I did not consider alternatives such as holding the online users in a database table. Should I use something other than a Group?

Also, if websocket.send channel is not used on Group('online-users').send({'data': 'data'}), then when is this channel used?

Thanks in advance

Regards

Andrew Godwin

unread,
Jan 2, 2017, 6:59:29 PM1/2/17
to django...@googlegroups.com
> However, Group('online-users').send({'data': 'data'}) does not send the data to websocket.send channel. It sends the data directly over the WebSocket.

It does, in fact, do exactly this - it seems you have got confused when you mention a consumer for the websocket.send channel, though, which is impossible - Daphne consumes those channels in order to relay data from them to the websocket.

If you need to send specific data per user, then your only option is to send invidually different messages, either to the reply channels (websocket.send) individually, or with one Group per user so that if a user has multiple windows open to the site they get all the messages.

Andrew

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/7636117a-e2e8-4946-9f56-5128caa75709%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Utku Gültopu

unread,
Jan 3, 2017, 2:57:34 AM1/3/17
to Django users
Then since I will be sending different data for every user, holding online users in a single Group does not make sense right?

But then where should I hold online users? In a database table? The documentation states using a Group is the best option because it automatically handles removing the users who have terminated their connection ungracefully (e.g, the client application has crashed and hence, it wasn't able to send a disconnect signal, which caused not running the 'websocket.disconnect' consumer, which would have handled removing this user from the online users list)

Where should I put the online users? Should I write my own boilerplate code to do what a Group does to remove inactive users from the Group, for what I will use to hold the online users?

Thanks in advance

Regards

Andrew Godwin

unread,
Jan 3, 2017, 11:09:28 AM1/3/17
to django...@googlegroups.com
My question to you is "why do you need a list of online users?". The answer to what storage to use varies based on what your answer to that question is.

Channels Groups are only suitable for broadcast of messages; they are not suitable for asking questions like "list all online users" or "is user X online" because of the scaling tradeoffs in there. If you want those sorts of questions, you will indeed have to manage online status yourself.

Andrew
Message has been deleted
Message has been deleted

Utku Gültopu

unread,
Jan 4, 2017, 6:22:38 AM1/4/17
to Django users
It is for sending fresh data to users. Let's say user A follows users B, C and D. However, only users A, B and C are online. Then only B's and C's data should be sent to user A. Because user D's data would be stale.

I thought of holding online users in a table of two columns, one column is a foreign key to User table and the other column is that user's reply channel. I would run a function every minute which would check if the WebSocket connections attached to reply channels are alive for every user in this table.
However I couldn't find how I can check if a WebSocket connection of a reply channel is alive. AFAIK, there isn't a function like 'is_alive'. I could send a PING to a channel but AFAIK, the reply would arrive at the 'websocket.receive' consumer.

So, is there a way to tell if the WebSocket connected to a channel is alive or not?

Andrew Godwin

unread,
Jan 4, 2017, 11:37:03 AM1/4/17
to django...@googlegroups.com
Not as part of Channels, since there's enough options and scaling challenges there that it's hard to pick a single strategy everyone would be OK with.

Channels' ability to give you correct pairs of `websocket.connect` and `websocket.disconnect` calls is pretty good these days - Daphne continually pings the websocket to see if it's alive, so the only time you won't get a disconnect message for a socket is if daphne dies or the disconnect channel gets full up.

Given that, you can probably do alive status with  just tracking in those two consumers and an expiry time for the 0.1% that don't get disconnects through properly. If you want something more robust and more demanding of resources, you can instead make the client application just send something down the socket every 20 seconds to say it's alive and then handle it in the receive consumer instead.

Andrew
Reply all
Reply to author
Forward
0 new messages