接続状態の復旧
接続状態の復旧は、一時的な切断後に、クライアントの状態(見逃したパケットを含む)を復元できる機能です。
この機能は、2023年2月にリリースされたバージョン 4.6.0 で追加されました。
リリースノートはこちらにあります。
免責事項
実際の状況では、Socket.IOクライアントは、接続品質に関係なく、一時的な切断を必然的に経験します。
この機能は、そのような切断に対処するのに役立ちますが、パケットとセッションを永久に保存したい場合(maxDisconnectionDurationをInfinityに設定することで)、復旧が常に成功することを保証することはできません。
そのため、クライアントとサーバーの状態を同期する必要がある場合に対処する必要があります。
使い方
接続状態の復旧は、サーバーで有効にする必要があります。
const io = new Server(httpServer, {
  connectionStateRecovery: {
    // the backup duration of the sessions and the packets
    maxDisconnectionDuration: 2 * 60 * 1000,
    // whether to skip middlewares upon successful recovery
    skipMiddlewares: true,
  }
});
予期しない切断(つまり、socket.disconnect()による手動切断ではない場合)が発生すると、サーバーはソケットのid、ルーム、およびdata属性を保存します。
その後、再接続時に、サーバーはクライアントの状態を復元しようとします。recovered属性は、この復旧が成功したかどうかを示します。
サーバー
io.on("connection", (socket) => {
  if (socket.recovered) {
    // recovery was successful: socket.id, socket.rooms and socket.data were restored
  } else {
    // new or unrecoverable session
  }
});
クライアント
socket.on("connect", () => {
  if (socket.recovered) {
    // any event missed during the disconnection period will be received now
  } else {
    // new or unrecoverable session
  }
});
基盤となるエンジンを強制的に閉じることで、復旧が機能していることを確認できます。
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();
    }
  }, 10000);
});
この例は、ブラウザで直接実行することもできます。
既存のアダプターとの互換性
| アダプター | サポート? | 
|---|---|
| 組み込みアダプター(インメモリ) | はい ✅ | 
| Redis アダプター | いいえ1 | 
| Redis Streams アダプター | はい ✅ | 
| MongoDB アダプター | はい ✅ (バージョン 0.3.0以降) | 
| Postgres アダプター | 作業中 | 
| Cluster アダプター | 作業中 | 
[1]パケットの永続化は、Redis PUB/SUBメカニズムとは互換性がありません。
内部の仕組み
- サーバーはハンドシェイク時にセッションIDを送信します(これは、公開されて自由に共有できる現在のid属性とは異なります)。
例
40{"sid":"GNpWD7LbGCBNCr8GAAAB","pid":"YHcX2sdAF1z452-HAAAW"}
where
4         => the Engine.IO message type
0         => the Socket.IO CONNECT type
GN...AB   => the public id of the session
YH...AW   => the private id of the session
- サーバーは各パケットにもオフセットを含めます(下位互換性のためにデータ配列の末尾に追加)。
例
42["foo","MzUPkW0"]
where
4         => the Engine.IO message type
2         => the Socket.IO EVENT type
foo       => the event name (socket.emit("foo"))
MzUPkW0   => the offset
復旧を成功させるには、サーバーが少なくとも1つのイベントを送信して、クライアント側のオフセットを初期化する必要があります。
- 一時的な切断が発生すると、サーバーはクライアントの状態を特定の遅延時間だけ保存します(アダプターレベルで実装)。 
- 再接続時に、クライアントはセッションIDと最後に処理したオフセットの両方を送信し、サーバーは状態の復元を試みます。 
例
40{"pid":"YHcX2sdAF1z452-HAAAW","offset":"MzUPkW0"}
where
4         => the Engine.IO message type
0         => the Socket.IO CONNECT type
YH...AW   => the private id of the session
MzUPkW0   => the last processed offset