ably-js icon indicating copy to clipboard operation
ably-js copied to clipboard

V2 usePresence errors

Open Elmosh opened this issue 9 months ago • 1 comments

Hey @VeskeR , following up on this issue Error: Connection closed #1753.

I have been using ably for a while, but after upgrading to v2 there’s a lot of errors popped up.

Along with the error in the mentioned issue that happens on page reload, there’s two more errors, they happens suddenly after staying on the same page for a long time (30+minutes) or to reproduce much faster; open on mobile then minimizing the browser for a couple of minutes and once it’s back opened the two errors appear:

Uncaught (in promise) Error: Unable to perform operation on channel: online-channel (not currently attached)
    at _ErrorInfo.fromValues (errorinfo.ts:54:34)
    at fromDeserialized (protocolmessage.ts:84:45)
    at deserialize (protocolmessage.ts:76:10)
    at WebSocketTransport.onWsData (websockettransport.ts:132:9)
    at wsConnection.onmessage (websockettransport.ts:81:18)
Presence Channel Error: Error: Channel detached
    at _RealtimeChannel.processMessage (realtimechannel.ts:524:13)
    at Channels2.processChannelMessage (baserealtime.ts:143:19)
    at _ConnectionManager.processChannelMessage (connectionmanager.ts:1809:34)
    at _ConnectionManager.processNextPendingChannelMessage (connectionmanager.ts:1793:12)
    at _ConnectionManager.onChannelMessage (connectionmanager.ts:1784:12)
    at WebSocketTransport.onProtocolMessage (transport.ts:198:32)
    at WebSocketTransport.onWsData (websockettransport.ts:131:12)
    at wsConnection.onmessage (websockettransport.ts:81:18)

Here’s the ably code (I’m using next with turbo):

provider:

"use client";

import * as Ably from "ably";
import { AblyProvider, ChannelProvider } from "ably/react";
import { ReactNode, useEffect, useState } from "react";

interface Props {
  currentUser: string | null;
  children: ReactNode;
}
const AblyContext: React.FC<Props> = ({ currentUser, children }) => {
  const [client, setClient] = useState<InstanceType<
    typeof Ably.Realtime
  > | null>(null);
  
    useEffect(() => {
    const newClient = new Ably.Realtime({
      authUrl: "/api/ablyToken",
      authMethod: "POST",
      clientId: currentUser!,
    });

    setClient(newClient);

    return () => {
      if (newClient) {
              newClient.close();
      }
    };
  }, [currentUser]);

  if (!client) {
    return null; 
  }
    return (
    <AblyProvider client={client}>
      <ChannelProvider
        channelName="online-channel"
      >
        {children}
      </ChannelProvider>
    </AblyProvider>
  );
};
export default AblyContext;

Presence:

import { usePresence, usePresenceListener } from "ably/react";
import useActiveList from "./useActiveList";

const useActiveChannel = () => {
    const { add, remove, set } = useActiveList();
    const { updateStatus } = usePresence(
    "online-channel",
    { status: "online" },
  );

  const { presenceData } = usePresenceListener("online-channel", (member) => {
    if (member.action === "enter" || member.action === "update") {
      add(member.clientId);
    } else if (member.action === "leave" || member.action === "absent") {
      remove(member.clientId);
    }
  });

  useEffect(() => {
    const memberIds = presenceData.map((m) => m.clientId);
    set(memberIds);
  }, [presenceData, add, remove, set]);

  return {};
};

export default useActiveChannel;

Side question, I use the presence channel to show online status for logged in users, but I also need to show those users status to not logged in users. Now I use the logged in userId as the clientId and for not logged in users it assigns “null” as the clientId. Is this an acceptable approach or is there a better way?

┆Issue is synchronized with this Jira Task by Unito

Elmosh avatar May 04 '24 22:05 Elmosh

Hello @Elmosh !

Thank you for reporting this issue and providing detailed information with code samples!

Couple of questions to help us identify the problem:

  1. After those errors occur, does the app continue to work as normal (e.g., it still receives messages from Ably servers, you're able to publish messages, and presence works as expected)?
  2. Do those errors occur in staging/production builds too, or only during development?

Regarding your other question:

I use the presence channel to show online status for logged in users, but I also need to show those users status to not logged in users

Using null for not logged-in users should work; the only downside is that you will also see users with the client id "null" in your presence set. To avoid that, you can use the skip parameter when calling usePresence to only enter presence when the user is actually logged in:

const { updateStatus } = usePresence(
  { channelName: "online-channel", skip: !isUserAuthenticated },
  { status: "online" },
);

In this case, you would also need to make sure not to call updateStatus if the user is not authenticated.

VeskeR avatar May 07 '24 14:05 VeskeR

  1. Yes the app and ably continued to work after the errors, and after a while the errors gets repeated again.
  2. The errors where so intrusive so I didn't deploy to staging/production and switched back to v1.

Regarding the other question; thanks for your insights but skip didn't work because the presenceData was empty for the skipped user, but I need the not logged-in users to still access the status for all other users.

Elmosh avatar May 07 '24 22:05 Elmosh

@Elmosh

  1. Yes the app and ably continued to work after the errors, and after a while the errors gets repeated again.
  2. The errors where so intrusive so I didn't deploy to staging/production and switched back to v1.

Thank you, I will investigate the issue and get back with more information.


Regarding the other question; thanks for your insights but skip didn't work because the presenceData was empty for the skipped user, but I need the not logged-in users to still access the status for all other users.

Did you by any chance add skip parameter to the usePresenceListener hook too? In this case presenceData returned by usePresenceListener will indeed be empty for not logged-in users. I think I should've been more explicit about where to add it.

Setup like this works for me locally:

const { updateStatus } = usePresence({ channelName: 'your-channel-name', skip: !isUserAuthenticated }, { foo: 'bar' });
const { presenceData } = usePresenceListener({ channelName: 'your-channel-name' }, (update) => {
  console.log(update);
});

where only usePresence hook is using skip parameter.

One more thought: I see you mentioned reverting back to ably-js v1. In v1 we had only one hook for presence, namely usePresence, which handles both entering presence and subscribing to presence data updates. If you used skip: true for non logged-in users in the usePresence hook in v1, then you would indeed neither enter presence nor receive data in presenceData. I think this is more likely what happened, as I was thinking about ably-js v2 when suggesting skip parameter.

To achieve the behavior you want in v1 you can use the subscribeOnly parameter there, which, when set to true, will prevent users from entering presence but they will remain subscribed to events:

const { presenceData, updateStatus } = usePresence(
  { channelName: 'your-channel-name', subscribeOnly: !isUserAuthenticated  },
  { foo: 'bar' },
  (update) => {
    console.log(update);
  }
);

VeskeR avatar May 08 '24 15:05 VeskeR

@VeskeR I will be happy to test the new v2 versions once you work the errors out.


You are correct I used skip with v1, I tried subscribeOnly and it's perfect for my setup for now till i migrate to v2, thanks for your insights.

Elmosh avatar May 09 '24 02:05 Elmosh

Hi @Elmosh ! I hope you are doing well.

In 2.1.0 release of ably-js we've added some improvements to usePresence hook behavior regarding presence re-entering including after being inactive for a while. Would you be able to test that version out and see if your issue still persists? Thank you!

VeskeR avatar Jun 03 '24 23:06 VeskeR

Closing this due to inactivity. Please try 2.1.0 release of ably-js and feel free to re-open the issue if the problem still persists.

VeskeR avatar Jun 20 '24 05:06 VeskeR