接続状態の復旧
接続状態の復旧は、一時的な切断後に、クライアントの状態(見逃したパケットを含む)を復元できる機能です。
この機能は、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