Redis publish/subscribe: see what channels are currently subscribed to

23,335

Solution 1

As of Redis 2.8 you can do:

PUBSUB CHANNELS [pattern]

The PUBSUB CHANNELS command has O(N) complexity, where N is the number of active channels.

So in your case:

redis-cli PUBSUB CHANNELS user*

would give you want you want.

Solution 2

There is currently no command for showing what channels "exist" by way of being subscribed to, but there is and "approved" issue and a pull request that implements this.

https://github.com/antirez/redis/issues/221
https://github.com/antirez/redis/pull/412

Due to the nature of this call, it is not something that can scale, and is thus a "DEBUG" command.

There are a few other ways to solve your problem, however. If you have reason to believe that a channel may be subscribed to, you can send it a message and look at the result. The result is the number of subscribers that got the message. If you got 0, you know that they're not there.

Assuming that your user_ids are incremental, you might be interested in using SETBIT to set a 1 or 0 to a user's offset bit to track presence. You can then do cool things like the new BITCOUNT to see how many users are online, and GETBIT to determine if a specific user is online.

The way I have solved your problem more specifically in the past is by signaling a subscription manager that I have subscribed to a channel. The manager then "pings" the channel by sending a blank message to confirm that there is a subscriber, and occasionally pings the channel thereafter to determine if the user is still online. Not ideal, but better than using DEBUG CHANNELS in production.

Solution 3

From version 2.8.0 redis has a pubsub command that would help in this case:

http://redis.io/commands/pubsub

Remark: currently the state of 2.8.0 is not stable yet (RC2)

Solution 4

I am unaware of any specific way to query what channels are being subscribed to, and you are correct that there isn't any key created when this happens. Also, I wouldn't use the KEYS command in production anyway, as it's really a debugging command.

You have the right idea about using a set to add the user when they're online, and then query this with SISMEMBER <set> <user_id> to determine if the messages should be sent to them or added to a Redis list for processing once they do come online.

You will need to figure out when a user logs off so you can remove them from the list of online users, but I don't know enough about your system to know exactly how you would go about that.

If the connected clients have the ability to send a message back to inform the server that the message(s) were consumed, you could use this to keep track of which messages should be stored for later retrieval.

Cheers, Mike

Share:
23,335
bignay2000
Author by

bignay2000

Updated on January 04, 2020

Comments

  • bignay2000
    bignay2000 over 4 years

    I am currently interested in seeing what channels are subscribed to in a Redis pub/sub application I have. When a client connects to our server, we register them to a channel that looks like:

    user:user_id

    The reason for this is I want to be able to see who's "online". I currently blindly fire off messages to a channel without knowing if a client is online since it's not critical that they receive these types of messages.

    In an effort to make my application smarter, I'd like to be able to discover if a client is online or not using the pub/sub API, and if they are offline, cache their messages to a separate redis queue which I can push to them when they get back online.

    This does not have to be 100% accurate, but the more accurate it is, the better. I'm assuming a generic key does not get created when a channel gets subscribed to, so I cannot do something as trivial as:

    redis-cli keys user* to find all online users.

    The other strategy I've thought of is just maintaining my own Redis Set whenever a user published or removes themselves from a channel (which the client automatically handles when they hop online and close the app). That would be an additional layer of complexity that I need to manage and I'm hoping there is a more trivial approach with the data that's already available.

  • Gabriel Samfira
    Gabriel Samfira about 11 years
    Great suggestion! I had the same need just now and managed to write around it by publishing 'null' to the channel to get the number of subscribers. Then in the listener I check if the message is None and skip it if it is. Cheers mate!
  • Bercovici Adrian
    Bercovici Adrian over 3 years
    Is this command available in StackExchange.Redis (.NET Redis driver ) ?