ably-js
ably-js copied to clipboard
V2 usePresence errors
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?
Hello @Elmosh !
Thank you for reporting this issue and providing detailed information with code samples!
Couple of questions to help us identify the problem:
- 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)?
- 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.
- Yes the app and ably continued to work after the errors, and after a while the errors gets repeated again.
- 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
- Yes the app and ably continued to work after the errors, and after a while the errors gets repeated again.
- 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 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.
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!
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.