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

Connection State Recovery fails for long-lived connections #5282

Open
bryghtlabs-richard opened this issue Jan 23, 2025 · 0 comments
Open

Connection State Recovery fails for long-lived connections #5282

bryghtlabs-richard opened this issue Jan 23, 2025 · 0 comments
Labels
to triage Waiting to be triaged by a member of the team

Comments

@bryghtlabs-richard
Copy link

bryghtlabs-richard commented Jan 23, 2025

Describe the bug
If the server does not periodically send the client messages, connection state recovery may fail unexpectedly.

To Reproduce

Socket.IO server version: 4.7.5, in-memory adapter

Server

import { Server } from "socket.io";

const io = new Server(3000, {
  connectionStateRecovery: {
    // the backup duration of the sessions and the packets
    maxDisconnectionDuration: 2 * 60 * 1000,
    // whether to skip middlewares upon successful recovery
    skipMiddlewares: true,
  }
});

io.on("connection", (socket) => {
  console.log(`connect ${socket.id}`);
  socket.emit("hello client", "Assigning offset to client");

  socket.on("disconnect", () => {
    console.log(`disconnect ${socket.id}`);
  });
});

We noticed this using a bespoke client, but appears to be a server-side issue. I've tried to mock up the client-side code accordingly.
Client

import { io } from "socket.io-client";

const socket = io({
  reconnectionDelay: 10000, // defaults to 1000
  reconnectionDelayMax: 10000 // defaults to 5000
});

socket.on("connect", () => {
  console.log("recovered?", socket.recovered);

  setTimeout(() => {
    if (socket.io.engine) {
      // close the low-level connection and trigger a reconnection
      socket.io.engine.close();
    }
  }, 3 * 60 * 1000);
});

Steps:

  1. Startup server, connect client to server, server emits an event to set client's recovery offset.
  2. Wait for 2x maxDisconnectionDuration without sending any events.
  3. Eventually Server will purge all buffered events on its side within maxDisconnectionDuration (+/- a minute or two).
  4. Cause client to reconnect
  5. Server cannot find appropriate offset because it has purged all buffered events.
  6. Client is assigned new ID.

Expected behavior
Connection State Recovery should succeed within maxDisconnectionDuration of disconnection, as long as the server must send at least one event, in order to initialize the offset on the client side.

It might help if server were to store offset of last queued packet in a separate variable, which could be checked even if restoreSession() cannot find the offset in the queue.

If server no longer relies upon pending message queue, we could then use Engine.IO PING/PONG events to trim queue(Once PONG is received, all events sent before the PING that triggered PONG are known to have arrived at the client).

Platform:

  • Client Device: electronic board game
  • OS: FreeRTOS
@bryghtlabs-richard bryghtlabs-richard added the to triage Waiting to be triaged by a member of the team label Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
to triage Waiting to be triaged by a member of the team
Projects
None yet
Development

No branches or pull requests

1 participant