socket.onDisconnect not working correctly on desktop devices

We’re experiencing an issue with the “socket.onDisconnect” callback of the Nakama Javascript SDK. We expect this callback to be executed when the connection to the server is lost, this is working as expected on mobile devices (browser), it’s called within a few seconds.

Unfortunately it seems that the callback is fired way later (multiple minutes) on desktop devices. We are aware of the various server side socket configuration settings, but for us it’s unclear which setting we need to adjust.

We also see some documentation regarding a ping/pong setup, which sounds good, but it seems like this is not implemented from the JavaScript client SDK?

How can we fix this issue?

  1. Versions: Nakama {3.10.0}, {Docker} {JavaScript client SDK}
  2. Server Framework Runtime language {TS/JS}

Hey Robin, currently we delegate to the underlying TCP stack for network disconnects on the socket in the JS client. This will result in a varying amount of time before the callback is fired depending on the browser/OS.We don’t currently have an ETA for when we add this at our JS SDK level.

Hi Luke,

Thanks for the reply. This is a blocking issue for us right now. We’re thinking of implementing our own ping/pong system, would that also be your recommendation here?

@RobinM can you share what browsers you’re seeing this issue on? And are you using desktop app frameworks based on browser tech such as Electron?

Hi Luke,

We see this at least on the latest Chrome (windows). The onDisconnect function is called, but after a few minutes instead of seconds compared to mobile devices.

How are you making the client lose connection? (e.g., turning off wifi, shutting down the server.) It may not matter but better to have the information.

We turn off WiFi, since the network throttling profile “offline” seems to not have an effect on websockets. I can setup a quick example client project do demonstrate the issue if needed.

Okay thanks. That’s alright – I think this is an issue specifically with Chrome as they do not do ping/pong under the hood like other browsers: 706002 - chromium - An open-source project to help move the web forward. - Monorail

I am looking now at implementing a ping/pong at the JS client level.

Thanks a lot Luke, much appreciated! Let me know in case we can help with anything from our end.

Hey @RobinM we’ve merged heartbeats into master and are finalizing our testing before making the next release:

Hey Luke,

That’s amazing, thanks a lot!

We’ll also do some testing on our end and let you know in case there are any issues.

Much appreciated! :slight_smile:

Thanks. It should be set for a release on Monday.

Hey @RobinM we’ve published a new release to NPM (v2.6.0) that should resolve your issue.

Hi Luke,

Thanks for the release. We’ve implemented this a couple of days ago. We do indeed now get a successful callback when a user is disconnect. However, this is taking ~ 20 seconds. We think this is due to one of the server side settings, but these are a bit unclear for us.

Which settings should we change to achieve a disconnect message within a few (3-5) seconds?

Hey @RobinM you can configure the timeout with setHeartbeatTimeoutMs on the socket. This is in Javascript.

The server independently may decide to disconnect from the client – those are the settings modified in the configuration that you’ve likely seen in the docs.

Hi Luke,

Thanks a lot, all clear!

It seems the socket.onDisconnect callback function is called very late. But we do see the Server unreachable from heartbeat error message very quickly (setHeartbeatTimeoutMs = 3000ms) after disabling WiFi. I’ve debugged this a bit, it’s calling WebSocketAdapterText:close, but takes some time before calling the WebSocketAdapterText.onClose callback (which calls the socket.onDisconnect)

My idea is that the WebSocket.close function is taking a while before completing since it’s doing a closing handshake on the socket (see: WebSocket.close() - Web APIs | MDN).

My suggestion would be to implement another callback on the WebSocketAdapterText, which will be called when the ping/pong failed. This way we can detect “connection problems” very soon. But also keep the onDisconnect callback, since a closed websocket is something else compared to a failed ping/pong.

Another option would be to completely ignore the onClose callback of the actual socket and call the onDisconnect callback when ping/pong is failing, but this might be tricky for some browsers.

Hey @RobinM you’re absolutely right and apologies for not catching the delay between the heartbeat timeout and the onclose event firing in our testing. I am going to have a think on the correct step forward here and update the JS client once I do.

I am sympathetic to the approach of a separate heartbeat callback, but my concern is most developers will either forget to attach to it or, if they do attach to it, call websocket.close() which would bring us to the same issue. It may still be the best approach – but going to have a think.

Hi Luke,

No worries regarding not catching the delay. I actually have the same concern with the extra callback approach after implementing it today the client library. We’ll test this approach on our side and I’ll let you know if there is indeed a delay.

Will create a PR if it’s working correctly and add you as a reviewer.

1 Like

PR: Implemented `onheartbeattimeout` callback for ping/pong. by robinmaree · Pull Request #151 · heroiclabs/nakama-js · GitHub

hello~I am using dotnet nakama client on windows platform and the server is also not receiving the disconnect callback. The query for online status is still true. is there any way to fix this please?