使用済み
NodeJS、Socket.io
問題
U1とU2という 2 人のユーザーがいて、Socket.io 経由でアプリに接続されているとします。アルゴリズムは次のとおりです。
- U1がインターネット接続を完全に失う (例: インターネットをオフにする)
- U2はU1にメッセージを送信します。
- インターネットがダウンしているため、 U1はまだメッセージを受信していません
- サーバがハートビートタイムアウトによりU1切断を検出
- U1は socket.io に再接続します
- U1はU2からメッセージを受信しません。ステップ 4 でメッセージが失われていると思います。
考えられる説明
なぜそれが起こるのか理解していると思います:
- on ステップ 4サーバーはソケット インスタンスとU1へのメッセージのキューも削除します
- さらに、ステップ 5 でU1とサーバーは新しい接続を作成します (再利用されません)。そのため、メッセージがまだキューに入れられていても、以前の接続はとにかく失われます。
助けが必要
この種のデータ損失を防ぐにはどうすればよいですか? 私は人々が永遠にアプリにハングアップするわけではないので、ハートビートを使用する必要があります。また、アプリの新しいバージョンをデプロイするときにダウンタイムをゼロにしたいので、再接続する可能性を引き続き与える必要があります。
PS私が「メッセージ」と呼ぶものは、データベースに保存できる単なるテキストメッセージではなく、配信を保証する必要がある貴重なシステムメッセージです。そうしないと、UIが台無しになります。
ありがとう!
追加1
私はすでにユーザー アカウント システムを持っています。さらに、私のアプリケーションはすでに複雑です。私はすでにこの種のものを持っているので、オフライン/オンラインのステータスを追加しても役に立ちません。問題は異なります。
ステップ 2 を確認してください。このステップでは、U1 がオフラインになるかどうかを技術的に判断することはできません。おそらく、インターネットの状態が悪いために、U1 が 2 秒間接続を失っただけです。したがって、U2 は彼にメッセージを送信しますが、U1 はインターネットがまだダウンしているため、メッセージを受信しません (ステップ 3)。ステップ 4 は、オフライン ユーザーを検出するために必要です。たとえば、タイムアウトは 60 秒です。最終的に、さらに 10 秒後に U1 のインターネット接続が確立され、彼は socket.io に再接続します。しかし、サーバー上で U1 がタイムアウトにより切断されたため、U2 からのメッセージは空間で失われます。
それが問題です。私は 100% 配信したくありません。
解決
- {} ユーザーのエミット (エミット名とデータ) を収集します。ランダムなemitID で識別されます。送信する
- クライアント側でエミットを確認します(emitIDでエミットをサーバーに送り返します)
- 確認された場合 - emitID で識別される {} からオブジェクトを削除します
- ユーザーが再接続した場合 - このユーザーの {} を確認し、{} 内の各オブジェクトに対してステップ 1 を実行してループします。
- 切断または/および接続時に、必要に応じてユーザーの {} をフラッシュします
// Server
const pendingEmits = {};
socket.on('reconnection', () => resendAllPendingLimits);
socket.on('confirm', (emitID) => { delete(pendingEmits[emitID]); });
// Client
socket.on('something', () => {
socket.emit('confirm', emitID);
});
解決策2(ちょっと)
2020 年 2 月 1 日追加。
これは実際には Websocket のソリューションではありませんが、それでも便利だと思う人がいるかもしれません。Websockets から SSE + Ajax に移行しました。SSE を使用すると、クライアントから接続して永続的な TCP 接続を維持し、サーバーからリアルタイムでメッセージを受信できます。クライアントからサーバーにメッセージを送信するには、単純に Ajax を使用します。レイテンシーやオーバーヘッドなどのデメリットはありますが、SSEはTCP接続なので信頼性を保証します。
Express を使用しているため、SSE にはこのライブラリhttps://github.com/dpskvn/express-sseを使用しますが、自分に合ったものを選択できます。
SSE は IE およびほとんどの Edge バージョンではサポートされていないため、 https ://github.com/Yaffle/EventSource というポリフィルが必要になります。