New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safari dropping web socket connection due to inactivity when page not in focus #2924
Comments
Running server with DEBUG=* shows the following: which I presume means that Safari closed the connection, not the socket server or client instance. However the strangest thing is that I've noticed Safari sometimes reconnects around 30 seconds to 1 minute later but other times it does not and stays disconnected until the page is brought to focus. It's incredibly frustrating to try and debug with such inconsistent behavior. |
It seems that sometimes it sporadically reconnects much later (like 10 minutes). Again, completely inconsistent under identical testing environments. |
@twistedpixel the reconnection delay is exponential (that is, something like: wait 500ms, try reconnect, wait 1000ms, try reconnect...) (source), so that may explain the behaviour. How about forcing to reconnect when the window gets the focus again? window.addEventListener("focus", () => socket.connect()); It may be related to primus/primus#348. |
Thanks for the info but the main issue is that I need the web socket permanently connected because it's used to send alerts to the user while they're away. Therefore window focus to reconnect isn't ideal. I think it's actually something more problematic specific to my machine/install anyway. I noticed the behaviour originally on my iMac so I decided to just wipe my MacBook with a fresh version of Safari and I'm not seeing the behavior there at all. I left a tab minimised for a whole day and it didn't disconnect once. I therefore tried going back to the iMac and removing all internet plugins and disabling all extensions but still I saw this behavior. Apple doesn't seem to provide any way to reinstall Safari completely other than deleting its preferences and certain other files. Or wiping the machine. Part of me wants to just start fresh but the developer in me would hate not knowing what the cause is. |
Actually, to your point about the exponential re-connects: surely the first re-connect would, as you say, be around 500ms after disconnect... so why would the server ignore it? There must be something preventing it from firing the re-connect. It's a bit weird because if I stick a |
This is typical browser behavior nowadays, even on desktops, unfortunately. |
I think I know what's happening. Safari is indeed the problem. I think all browsers cap the setTimeout and setInterval values at 1000 when the tab is not in focus. Safari - stupidly - caps it at 1000 and does something like exponentially adding a delay that results in each iteration taking doubly as long as the last. This is why the connection dies; socket.io's internal timeouts are being delayed/dropped, explaining why reconnects aren't happening when they should. So basically, Apple has decided to go against the grain, as usual, resulting in a poor user experience. They're really good at this these days. I haven't discovered why it's affecting the iMac and not the MacBook (I'd have expected the reverse) but I'll keep testing and see if I can pinpoint the exact reason. |
@twistedpixel it's not only Safari. See http://blog.strml.net/2017/01/chrome-56-now-aggressively-throttles.html In Primus we worked around the issue by reversing the direction of the heartbeat messages (primus/primus#534). |
@lpinca The entire time I was trying to figure out this issue I was wondering that very thing. Thanks for the info! I have been looking at Primus but I didn't want to have to refactor my entire code base so soon. Seems it could be worth the effort though. |
@twistedpixel my point is that the same can probably be done in Engine.IO so there is no need to migrate to Primus. |
FWIW, Safari Tech Preview does not seem to be affected by the additional throttling. Perhaps Apple reversed their decision. It's still throttling to 1000ms but doesn't seem to be adding anything further. |
I am experiencing the same issue on iOS 12 Safari. If I re-open my safari, the websocket connection is gone. Is there a clean workaround to keep the socket alive? |
AFAIK iOS Safari suspends certain processes when Safari is backgrounded (to prevent battery drain) and websocket connections are almost certainly one such process. It’s unlikely you’ll find a workaround on mobile devices. |
OK. But I still can reconnect if I add an event listener like onwindowfocus or something? |
Has anyone implemented a workaround? we are interested in looking at options and wonder if others are already experimenting |
Rather than using focus events, you'll need to use the Page Visibility API to detect when a mobile app window has been backgrounded. |
I bumped into the issue with Azure SignalR and thanks to @techpeace suggestion currently using the Page Visibility API to close the connection on page hide and reconnect it again when the page is visible.But bumped into problems with quick switching of tabs, which can send multiple events. Currently looking into debouncing the events..Also general advice found on the web discourages any kind of handling based on user agent detection..so my solution is to use the page visibility API irrespective of the user agent. |
SolutionsI tested for several hours with all 3 of these browsers, changing the
I believe the best solution to be changing |
I think that's because the current version of socket.io relies on the setTimeout on the client side, which may not be as reliable as expected. We'll include this in the v3, as it is a breaking change. Related: primus/primus#348 |
@darrachequesne i ma also facing that when on mobile if my phone screen goes in standby and i open the browser again on mobile, socket io disconnects the chat. plz fix this. it will be huge relieve. |
any update on this bug in socket io? in my app when user tries to upload a file from their mobile browser, and when upload dialog box opens, socket io disconnects them if they take 15 seconds or more to select a file. if they switch to another page or tab, after 15 sec , socket io again disconnects them, is there anyway to fix this and keep socket io alive/connected even if user is not on page/document focused? |
I have fixed this issue with Visibility API. Main issue with Safari for me - it has no time to close socket on visible.hidden === true, so you need to close websocket after device is unlocked, and initiate it again. |
@JustFly1984 Do you have some sample code for that. I've got the visibility detection working properly, but I can't get the socket to reconnect. |
So now this is happening with MacOS Safari too, FYI. |
Thanks for getting back to me JustFly1984. Actually, in the end, I didn't need the visibility API. I simply need to add timeouts. Once I did this, I no longer had the connection issues on iOS Safari.
|
For future readers: this should be fixed in latest versions due to two changes:
The server now sends PING packets, so the client will not be declared dead when it does not send a PING in time due to timer throttling. See also: https://socket.io/blog/engine-io-4-release/#heartbeat-mechanism-reversal
|
Year 2023. This is still happening with websockets, I'll try @JustFly1984's method. or I'll use socket.io, I guess. |
You want to:
Current behaviour
Not sure if this is a known issue (I tried searching but found nothing). Safari for Mac appears to be silently dropping websocket connections due to inactivity/idle if the page/tab is not in focus.
Steps to reproduce (if the current behaviour is a bug)
Make Safari tab/page not in focus; log websocket events.
Expected behaviour
Websockets should be kept alive via the heartbeat functionality. Not seeing this behavior in other browsers so unlikely to be my code.
Setup
Other information (e.g. stacktraces, related issues, suggestions how to fix)
Is this possibly some sort of power-saving feature that is overriding/ignoring the heartbeats?
The text was updated successfully, but these errors were encountered: