ably / ably-js

Javascript, Node, Typescript, React, React Native client library SDK for Ably realtime messaging service
https://ably.com/download
Apache License 2.0
313 stars 55 forks source link

Detach channel in `ChannelProvider` #1795

Open ttypic opened 3 months ago

ttypic commented 3 months ago

We should detach channel if there is no ChannelProvider associated with it.

The reason for doing this is that the SDK user should be able to detach from the channel to stop receiving messages from it. In react-hooks, we fully control the channel lifecycle. Automatic detachment seems more reasonable and better than manual detachment using the Ably client. The best place to do this is inside ChannelProvider because this component indicates the intent to use the channel. If it no longer exists, it means we no longer need this channel attached.

┆Issue is synchronized with this Jira Task by Unito

ianb-pomelo commented 2 weeks ago

Is there a shorter term mitigation for this? We switch our channels somewhat regularly and without this our channels are never detached and have hit the 200 channel limit even though most are unused/unsubscribed (and are also billed for the channels)

ttypic commented 2 weeks ago

It depends on what you want to achieve. Based on your business logic, you can invoke the detach() method when you no longer need the channel. Additionally, you can create a wrapper around the ChannelProvider:

const DetachableChannelProvider = (channelProviderProps) => {
   const ablyClient = useAbly();
   const { channelName } = channelProviderProps;

  useEffect(() => {
      // it's better to explicitly attach to the channel in this case
      ablyClient.channels.get(channelName).attach();
      return () => ablyClient.channels.get(channelName).detach();
  }, [channelName])

  return <ChannelProvider {...channelProviderProps} />;
}
ianb-pomelo commented 1 week ago

Thanks! I've tried to add this but occasionally get an error when switching channels quickly that I can't seem to resolve.

The error is

useChannel.js:56 Uncaught (in promise) Error: Channel detached
    at _RealtimeChannel.processMessage (ably.js:6240:81)
    at Channels2.processChannelMessage (ably.js:6657:19)
    at _ConnectionManager.processChannelMessage (ably.js:5627:34)
    at _ConnectionManager.processNextPendingChannelMessage (ably.js:5613:12)
    at _ConnectionManager.onChannelMessage (ably.js:5606:12)
    at WebSocketTransport.onProtocolMessage (ably.js:4042:32)
    at WebSocketTransport.onWsData (ably.js:7354:12)
    at wsConnection.onmessage (ably.js:7308:19)

which seems to be caused by attempting to re-subscribe to a channel that is detaching/detached. Is there anything I can do to handle this? It seems like the handleChannelMount is throwing but because it's in an effect I don't think I can handle it

ttypic commented 1 week ago

Hey @ianb-pomelo,

I apologize for the delay. I missed the notification about your message. Could you please attach verbose logs or share a reproducible example? I’m having difficulty reproducing the issue you’re facing.