Skip to content
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

Prevent socket io from emitting ping timeout for inactive or not focused browser page in mobile browsers chrome, firefox and safari. #3507

Closed
1 task done
FaizanZahid opened this issue Nov 2, 2019 · 6 comments
Milestone

Comments

@FaizanZahid
Copy link

FaizanZahid commented Nov 2, 2019

You want to:

  • report a bug

Current behaviour

What is actually happening?

I have a simple chat app using socket io. Very similar to the socket io chat official demo. Socket io goes to ping timeout on all mobile browsers whenever the user minimizes the page or opens another app or page gets out of foucs.

In my web app whenever, the user clicks on file input upload from their chrome/firefox/safari browser on mobile, it opens up the phone dialog box to select the file from galley to select and upload. During this time (my chat page gets out of focus due to visibility), when user is searching for a file, and after exact 30 seconds, socket io client issues ping timeout, and the person chat is disconnected.

In my application level, i am doing a reconnect if socket io goes to ping timeout for whatever reason, but that doesn't fix my problem, because if the user clicks on 1 file after 31 seconds, then that image file is not sent in chat, because socket io was timed out during that time, and it takes few seconds to reconnect, when the user's focus is back on the browser tab. So the file upload action is lost, because file is uploaded but socket io connection was on ping timeout. so when it reconnects, the selected file upload is never sent to the other connected user.

Steps to reproduce (if the current behaviour is a bug)

Please check relevant stackoverflow question:
https://stackoverflow.com/questions/58667207/prevent-socket-io-from-ping-timeout-on-inactive-or-not-focused-browser-page-on-c

Expected behaviour

Whenever on mobile or desktop browsers, if a user navigates away from socket io chat page and comes back, socket io should still keep the client connected, and should not issue a ping timeout event and cause disconnect after 30 seconds. It should keep chat active no matter how long a person is out of focus of the page.

What is expected?

Setup

  • OS: Android and iOS
  • browser: happening on safari, firefox, chrome (android and iphones)
  • socket.io version: 2.2.0 (same issue happening on 2.3.0 too, i tried upgrading my client and socket io both)

Other information (e.g. stacktraces, related issues, suggestions how to fix)

I tried detecting whenever user's page focus is out, using this code,

document.addEventListener("visibilitychange", onchange);
from Is there a way to detect if a browser window is not currently active?

and then once page is not in focus, i used setinterval to emit my custom heartbeat event to my server code. (just to keep socket io from talking to server to keep connection alive).. This works fine for desktop browsers, But on all mobile browsers, whenever user's page is not in focus, i.e if a user minimizes the browser, opens a new app, or goto select file upload screen, socket io times out after 30 seconds or sometimes even faster then this.

My client js code:

`var beating;
//function to detect if user gone out of page

//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
//socket = this.socket;
if (document.hidden) {
// console.log();
$('#logwrapper').prepend(" üser is outside \n ", socket.id);

//emit on server after every 10 seconds
beating = setInterval(function () {
  $('#logwrapper').prepend(" inside interval emitting");

  socket.emit('heartbeat', { data: "a" });
}, 15000)

} else {
//console.log("üser is in");
$('#logwrapper').prepend(" üser is in \n ", socket.id);
console.log("çlearing inteval beating from visiblity");
clearInterval(beating);
}
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);`

And my server.js code

//socket events for heartbeat socket.on("heartbeat", function (data) { console.log("socket is outside ", data, socket.id); }); //socket events for heartbeat , just log it so that my client remains active and keep communicating with server, to avoid socket io timeout
I also tried adjusting my socket io server & client timeout configs, but that is not making any difference, after user minimise the browser page on mobile, chorme, firefox & safari, socket io client emits ping timeout after 30 seconds or so,

How can i increase this timeout, so socket io connection remains active (don't ping timeout) for longer time (as much as i want)?

Here are my server.js configs for socket io:

var io = require("socket.io")( 231, { transports: ["websocket", "polling"] }, server, { path: '/socket.io', serveClient: true, // below are engine.IO options pingInterval: 25000, //was 10k, how many ms before sending a new ping packet, => how often to send a ping pingTimeout: 30000, //should be above 30k to fix disconnection issue how many ms without a pong packet to consider the connection closed upgradeTimeout: 20000, // default value is 10000ms, try changing it to 20k or more agent: false, cookie: false, rejectUnauthorized: false, reconnectionDelay: 1000, reconnectionDelayMax: 5000, maxHttpBufferSize: 100000000 //100 mb } );
and my socket io client configs:

this.socket = io.connect('https://appurl.com', { reconnection: true, reconnectionDelay: 1000, reconnectionDelayMax: 5000, reconnectionAttempts: Infinity, //our site options transports: ["polling", "websocket"], secure: true, rejectUnauthorized: false, forceNew: false, timeout: 60000 });
Basically on all mobile browsers, as long as page gets out of focus, my JS code stops executing, and whenever the page focused again, JS exection resumes, looks like its not a problem with setinterval or settimeout. How can i keep executing my client JS code to keep socket io from doing ping timeout?

I also tried a similar logic using settimeout, https://codepen.io/Suhoij/pen/jAxtn

this code works in codepen on all mobile browsers, even if i minimise this page on my mobile and come back again, the timer is still executing, but the same code when i run on my app, it doesn't work in my code. Why? Is socket io pausing my all client.js code when page is not in focus? OR is my logic not correct? I also tried emitting an event from my server.js after every 2 second to all clients, but the emits stop when page is not in foucs on mobile :/

Relevant socket io issues: #2769

@Twois
Copy link

Twois commented Nov 5, 2019

I guess this issue is not socket.io related issue, because on mobile the apps has limitations like they are closed or paused after 30 second. Until the browser not request background permission from the user, they will be closed and any js code will stop work.

I solved the same issue, I use socket.io with angular and I wrote a wrapper service around socket.io. I wrote a queue system, so when my client want to send message to the server (it could be text or file, whatever), first I store the message in an array with Id, and I listen to connection changes, and when the connection reestablished I send the messages from the queue. Of course I use IDs to identify the messages, to remove from the queue when the server received them, and prevent to send the message more times.

@FaizanZahid
Copy link
Author

@Twois can you provide me a demo version with code example of socket io with a queue mechanism for sending msgs only when connection is reestablished and also a way for socket io to reconnect automatically?

@nidhaloff
Copy link

@FaizanZahid I'm having a similar issue. My web page works fine if less than ~30 clients are connected, otherwise my server starts randomly disconnecting some clients. I debugged the problem and turns out that the server thinks that the clients are dead or not connected anymore so it fires the disconnection event "ping timeout". Does anyone have a solve for this

@guyeatspants
Copy link

What I've done is to ping the server from the client and on receiving the ping the server pongs i like to call it every 2 seconds if the user is not on active. I've been able to keep all connections active.

@jpflexgen
Copy link

jpflexgen commented Nov 2, 2021

notes from chrome devtools capture with Vinay where bug was recreated:

335 ping timeout

"response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Content-Type",
              "value": "text/plain; charset=UTF-8"
            },
            {
              "name": "Content-Length",
              "value": "103"
            },
            {
              "name": "Access-Control-Allow-Origin",
              "value": "*"
            },
            {
              "name": "Set-Cookie",
              "value": "io=00iE84mv80SC1b8JAAG7; Path=/; HttpOnly; SameSite=Strict"
            },
            {
              "name": "Date",
              "value": "Tue, 02 Nov 2021 18:10:13 GMT"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            }
          ],
          "cookies": [
            {
              "name": "io",
              "value": "00iE84mv80SC1b8JAAG7",
              "path": "/",
              "domain": "10.1.100.10",
              "expires": null,
              "httpOnly": true,
              "secure": false,
              "sameSite": "Strict"
            }
          ],
          "content": {
            "size": 103,
            "mimeType": "text/plain",
            "compression": 0,
            "text": "96:0{\"sid\":\"00iE84mv80SC1b8JAAG7\",\"upgrades\":[\"websocket\"],\"pingInterval\":25000,\"pingTimeout\":5000}2:40"
          },
          "redirectURL": "",
          "headersSize": 246,
          "bodySize": 103,
          "_transferSize": 349,
          "_error": null

4935 admin invalid namespace

related socket.io issues on github ( not FlexGen issues )

we use socket.io 2.3 on web server

@darrachequesne
Copy link
Member

For future readers:

This should be fixed in latest versions, due to:

Which means the Socket.IO client does not rely on timers which can be throttled for tabs put in background.

Please reopen if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants