I'd start with a solution based on three layers of Actors. From Redis feed to Websockets:
- ChannelDispatcherActor
- ChannelActor
- WebsocketActor
ChannelDispatcherActor is a singleton that receives a stream of Publish(Channel, Content) from the Redis feed, and maintains a private map of Channel to ChannelActor with lazy-create semantics. It accepts messages
- Subscribe(Channel, WebsocketActor) - lookup ChannelActor for Channel, create if necessary, forward to ChannelActor
- Unsubscribe(Channel, WebsocketActor) - same - lookup & forward
- Publish(Channel, Content) - same - lookup & forward
ChannelActor is one-per-Channel and maintains a set of WebsocketActors listening to its channel. It accepts messages
- Subscribe(Channel, WebsocketActor) - add WebsocketActor to listeners, also context.watch(actorref)
- Unsubscribe(Channel, WebsocketActor) - remove from listeners
- Terminated(WebsocketActor) - remove from listeners
- Publish() - send to each in listeners
WebsocketActor is one-per-websocket and maintains a list of Channels a websocket is subscribed to, and publishes traffic it receives from ChannelActors to its websocket. To manage to a Channels it sends ChannelDispatcherActor Subscribe/Unsubscribes. It terminates itself when the websocket is closed, and WebsocketActors cleanup their listener lists through then watch()es.
Lots of optimizations to be made, and this does nothing for fault tolerance, but those are separate posts.
Happy hakking !!