Connection State Recovery fails if client reconnects before server emits any events ("Zero-Event" reconnect)
メンテナーはふだん 2 日以内に返信
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 56/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- javascript, node.js, typescript
調査の方向性
socket.io/lib/namespace.ts のリカバリーゲートから開始し、socket.io-client が _lastOffset をどのように保持し、再接続ハンドシェイクを送信するかを追跡します。イベントが 0 件のパスを restoreSession() および既存の接続状態リカバリーの動作と比較します。事前にイベントがない状態での再接続によってセッション ID、ルーム、データが保持され、socket.recovered が true として報告されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
When connectionStateRecovery is enabled, a client that connects, joins rooms, and disconnects before the server emits any events cannot recover its session on reconnection.
Even if the client reconnects within maxDisconnectionDuration, socket.recovered evaluates to false, a new socket.id is generated, and room memberships / socket.data are lost. This happens because _lastOffset on the client is undefined in the zero event case, causing the server's typeof offset === "string" check in namespace.ts to fail and bypass restoreSession().
To Reproduce
Socket.IO server version: 4.8.1
Server
import { Server } from "socket.io";
const io = new Server(3000, {
connectionStateRecovery: {
maxDisconnectionDuration: 2 * 60 * 1000,
},
});
io.on("connection", async (socket) => {
if (socket.recovered) {
console.log(`RECOVERED: ${socket.id} (rooms: ${Array.from(socket.rooms).join(", ")})`);
return;
}
console.log(`INITIAL CONNECT: ${socket.id}`);
await socket.join("room:alerts");
// Deliberately no events emitted to the client
});
Socket.IO client version: 4.8.1
Client
import { io } from "socket.io-client";
const socket = io("http://localhost:3000", {
reconnection: true,
});
socket.on("connect", () => {
console.log(`connect ${socket.id} (recovered: ${socket.recovered})`);
// Simulate a brief network drop shortly after connecting
setTimeout(() => {
socket.io.engine.close();
}, 200);
});
Expected behavior
When the client reconnects after the transient drop, the server should recognize the pid, restore the previous session (socket.id, room memberships, socket.data), and set socket.recovered = true.
Platform:
- Device: PC / Mac / Server
- OS: Linux / macOS / Windows
- Node.js version:
20.x/22.x
Additional context
-
Root Cause: In
socket.io-client,_lastOffsetremainsundefineduntil a packet of typeEVENTwith an offset is received. On reconnect, the handshake sends{ pid: "<id>", offset: undefined }. Insocket.io/lib/namespace.ts, recovery is gated by:if ( this.server.opts.connectionStateRecovery && typeof sessionId === "string" && typeof offset === "string" ) { session = await this.adapter.restoreSession(sessionId, offset); }Because
offsetisundefined,restoreSession()is skipped entirely despite having a valid activepid. -
Impact: Quiet subscriber channels (e.g. alert rooms, idle game lobbies) lose session state on brief network blips unless application code manually emits a synthetic dummy event on first connect to "prime"
_lastOffset. -
Potential Solutions:
- Include the current server stream offset in the initial
CONNECT(packet type0) handshake payload alongside{ sid, pid }so_lastOffsetis initialized at connection time. - Allow
restoreSession(sessionId, offset)to run whenoffsetisundefined, restoringid,rooms, anddatawithout replaying events.
- Include the current server stream offset in the initial
- 主要言語
- TypeScript
- スター
- 63.2k
- フォーク
- 10.3k
- 平均マージ
- 3時間 24分
- マージ済み PR(30日)
- 1
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
socketio/socket.io のほかの issue
-
難易度 1/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 2 日以内に返信
-
Can't set response headers in Server.handleUpgrade対応中かも @MsfPablo が 60 日前に担当しました。 オープンquestion
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
socketio/socket.io#5497 · コメント 2 件 ·
メンテナーはふだん 2 日以内に返信
-
WebTransport ignores query parameters in URL対応中かも @cyphercodes が 149 日前に担当しました。 オープンneeds major release question
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
socketio/socket.io#5496 · コメント 3 件 ·
メンテナーはふだん 2 日以内に返信
-
"Basic CRUD application" can't be started with Angular client対応中かも @lazerg が 7 日前に担当しました。 オープンto triage
難易度 3/5 1〜2日 初心者へのやさしさ 65/100
メンテナーはふだん 2 日以内に返信
-
enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
socketio/socket.io#5512 · コメント 6 件 · リアクション 4 件 ·
メンテナーはふだん 2 日以内に返信
socketio/socket.io の issue をすべて見る
似ている issue
-
affected/v17 affected/v18 area/frontend type/bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
umbraco/Umbraco-CMS#24186 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
better-auth/better-auth#11723 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
area: docs difficulty: easy documentation good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
Worker-Erstellung bricht langsame Git-Worktree-Checkouts nach 20 Sekunden ab対応中かも @KajoVanBuyten が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
AgentSystemLabs/agent-office#367 ·
メンテナーはふだん 1 日以内に返信