serverpod / serverpod

Serverpod is a next-generation app and web server, explicitly built for the Flutter and Dart ecosystem.
BSD 3-Clause "New" or "Revised" License
2.37k stars 217 forks source link

Add ability to subscribe to multiple channels in one API call #2353

Open lukehutch opened 3 weeks ago

lukehutch commented 3 weeks ago

Is your feature request related to a problem? Please describe.

I wrote my own chat server, since I ran into several issues with serverpod_chat.

For my application, every user in the system (potentially millions of users) may have joined hundreds of chat channels in the history of using the app (one channel for each dating match, and one channel for every event the user is an attendee of).

One of the design decisions when I built my own chat solution was to subscribe the user just once to a Redis channel, using the channel name 'user_$userId'. Then on the server, when a message is sent to a channel, I loop through all the members of the channel, and forward the message to each user by their userId.

This is inefficient, because not every user will be online, but also because Redis does not have a multicast / fan-out version of PUBLISH.

The alternative is worse though: I could have instead subscribed each user to the id of every chat channel they have ever joined, i.e. 'chat_${channelIds[i]}', which could mean hundreds of subscriptions. This is also inefficient on Redis memory usage, because most of those chat channels will be dead (no recent messages, and very low likelihood of new messages). However, it is more efficient on CPU usage when a message is sent, because it can be delivered to just the users that are online and subscribed to a specific chat channel (there is no longer a need for fan-out if I implement fan-in like this).

Currently Serverpod doesn't support fan-in / subscribing to multiple channels in a single API call. You have to call addListener(session, String channelName, listener) (in message_central.dart) for every channel. But Redis supports subscribing to multiple channels at once, via SUBSCRIBE [channels...].

Describe the solution you'd like

I would like a new method addListenerMultiple(session, List<String> channelNames, listener) that subscribes to a list of channels in a single Redis call.

Describe alternatives you've considered

There are no efficient alternatives.

lukehutch commented 3 weeks ago

I created a Redis issue to see if they would consider supporting fan-out... https://github.com/redis/redis/issues/13327

But I think at least simply adding multi-subscribe to Serverpod would be pretty useful for messaging platforms.

lukehutch commented 3 weeks ago

So apparently Redis streams to support fan-out, and they function as a message queue. Why was pub/sub chosen over streams?