メインコンテンツへスキップ
バージョン: 4.x

配信保証

メッセージの順序

Socket.IO は、どの低レベルトランスポートが使用されていても(HTTP ロングポーリングから WebSocket へのアップグレード中でも)、メッセージの順序を保証します。

これは以下のことによって実現されます。

socket.emit("event1");
socket.emit("event2");
socket.emit("event3");

上記の例では、イベントは常に相手側で同じ順序で受信されます(実際に到着する場合、下記参照)。

メッセージの到着

最大1回

デフォルトでは、Socket.IO は 最大1回 の配信保証を提供します。

  • イベントの送信中に接続が切断された場合、相手側がそれを受信した保証はなく、再接続時に再試行は行われません。
  • 切断されたクライアントは、再接続までイベントをバッファリングします(ただし、前の点は依然として適用されます)。
  • サーバーにはそのようなバッファがないため、切断されたクライアントが見逃したイベントは、再接続時にそのクライアントに送信されません。
情報

現時点では、追加の配信保証はアプリケーションで実装する必要があります。

少なくとも1回

クライアントからサーバーへ

クライアント側からは、確認応答とタイムアウトを使用して、少なくとも1回の保証を実現できます。

function emit(socket, event, arg) {
socket.timeout(2000).emit(event, arg, (err) => {
if (err) {
// no ack from the server, let's retry
emit(socket, event, arg);
}
});
}

emit(socket, "foo", "bar");

上記の例では、クライアントは指定された遅延の後、イベントの送信を再試行するため、サーバーは同じイベントを複数回受信する可能性があります。

注意

その場合でも、ユーザーがタブを更新すると、保留中のイベントは失われます。

サーバーからクライアントへ

サーバーから送信されたイベントの場合、追加の配信保証は、次のように実装できます。

  • 各イベントに一意のIDを割り当てる
  • イベントをデータベースに永続化する
  • クライアント側で最後に受信したイベントのオフセットを保存し、再接続時に送信する

クライアント

const socket = io({
auth: {
offset: undefined
}
});

socket.on("my-event", ({ id, data }) => {
// do something with the data, and then update the offset
socket.auth.offset = id;
});

サーバー

io.on("connection", async (socket) => {
const offset = socket.handshake.auth.offset;
if (offset) {
// this is a reconnection
for (const event of await fetchMissedEventsFromDatabase(offset)) {
socket.emit("my-event", event);
}
} else {
// this is a first connection
}
});

setInterval(async () => {
const event = {
id: generateUniqueId(),
data: new Date().toISOString()
}

await persistEventToDatabase(event);
io.emit("my-event", event);
}, 1000);

不足しているメソッド(fetchMissedEventsFromDatabase()generateUniqueId()persistEventToDatabase())の実装はデータベース固有であり、読者の課題として残されます。

参考資料