私はjqueryで次のクエリを持っています。これは、Nginx のロング ポーリング モジュールを使用して設定された Nginx サブスクライブ/パブリッシュ ペアの「パブリッシュ」アドレスを読み取ります。
function requestNextBroadcast() {
// never stops - every reply triggers next.
// and silent errors restart via long timeout.
getxhr = $.ajax({
url: "/activity",
// dataType: 'json',
data: "id="+channel,
timeout: 46000, // must be longer than max heartbeat to only trigger after silent error.
error: function(jqXHR, textStatus, errorThrown) {
alert("Background failed "+textStatus); // should never happen
getxhr.abort();
requestNextBroadcast(); // try again
},
success: function(reply, textStatus, jqXHR) {
handleRequest(reply); // this is the normal result.
requestNextBroadcast();
}
});
}
コードはチャット ルームの一部です。送信されたすべてのメッセージは、null rply (200/OK) で返信されますが、データは公開されます。これは、データが戻ってきたときにサブスクライブ アドレスを読み取るためのコードです。
タイムアウトを使用すると、チャットルームのすべての人が 30 秒から 40 秒ごとに単純なメッセージを送信します。何も入力しなくても、このコードが読み取るデータは十分にあります。40 秒あたり少なくとも 2 件、場合によってはそれ以上のメッセージです。 .
コードは EI と Firefox で 100% 堅実です。しかし、Chrome では約 5 回の読み込みで 1 回失敗します。
Chrome が失敗すると、46 秒のタイムアウトが発生します。
ログには、一度に 1 つの /activity ネットワーク リクエストが未処理であることが示されます。
私はこのコードを 3 日間クロールして、さまざまなアイデアを試しています。そして毎回、IE と Firefox は問題なく動作し、Chrome は失敗します。
私が見た 1 つの提案は、呼び出しを同期させることですが、ユーザー インターフェイスが長時間ロックされるため、明らかに不可能です。
編集 - 部分的な解決策があります:コードは次のとおりです
function requestNextBroadcast() {
// never stops - every reply triggers next.
// and silent errors restart via long timeout.
getxhr = jQuery.ajax({
url: "/activity",
// dataType: 'json',
data: "id="+channel,
timeout: <?php echo $delay; ?>,
error: function(jqXHR, textStatus, errorThrown) {
window.status="GET error "+textStatus;
setTimeout(requestNextBroadcast,20); // try again
},
success: function(reply, textStatus, jqXHR) {
handleRequest(reply); // this is the normal result.
setTimeout(requestNextBroadcast,20);
}
});
}
その結果、$delay (15000) が発生するまで応答が遅延することがあります。その後、キューに入れられたメッセージがすぐに到着し、追跡できません。この新しい配置では、メッセージをドロップさせることができませんでした (ネットワークの最適化をオフにしてのみテストしました)。
遅延がネットワークの問題によるものであるとはとても思えません。すべてのマシンは 1 台の実マシン内の VM であり、ローカル LAN の他のユーザーはいません。
編集 2 (金曜日 2:30 BST) - promise を使用するようにコードを変更しました - アクションの POST は同じ症状を示し始めましたが、受信側は正常に動作し始めました! (????????????)。これは POST ルーチンです。一連のリクエストを処理して、一度に 1 つのみが未解決であることを確認します。
function issuePostNow() {
// reset heartbeat to dropout to send setTyping(false) in 30 to 40 seconds.
clearTimeout(dropoutat);
dropoutat = setTimeout(function() {sendTyping(false);},
30000 + 10000*Math.random());
// and do send
var url = "handlechat.php?";
if (postQueue.length > 0) {
postData = postQueue[0];
var postxhr = jQuery.ajax({
type: 'POST',
url: url,
data: postData,
timeout: 5000
})
postxhr.done(function(txt){
postQueue.shift(); // remove this task
if ((txt != null) && (txt.length > 0)) {
alert("Error: unexpected post reply of: "+txt)
}
issuePostNow();
});
postxhr.fail(function(){
alert(window.status="POST error "+postxhr.statusText);
issuePostNow();
});
}
}
約 8 回に 1 回のアクションで、handlechat.php の呼び出しがタイムアウトになり、アラートが表示されます。アラートが OK になると、キューに入れられたすべてのメッセージが到着します。
また、handlechat の呼び出しが、他のユーザーに表示されるメッセージを書き込む前に停止していることにも気付きました。PHPによるセッションデータの扱いがおかしいのではないかと思っています。セッション データが破損しないように呼び出しを慎重にキューに入れることを知っているので、別のブラウザまたは別のマシンを使用するように注意してきました。php ワーカー スレッドは 2 つしかありませんが、php は /activity の処理や静的コンテンツの提供には使用されません。
また、nginx ワーカーまたは php プロセッサが不足しているのではないかと考えたので、それらを引き上げました。物事を失敗させることはより困難になりましたが、それでも可能です。私の推測では、/activity 呼び出しは 30 回に 1 回失敗し、メッセージはまったくドロップされません。
そして、ご意見をお寄せいただきありがとうございます。
所見のまとめ。
1) しばらくの間コードに含まれていた Chrome のバグです。
2) 運が良ければ、バグは送信されない POST として表示され、タイムアウトになると、Chrome は POST の繰り返しが成功するような状態になります。
3) $.ajax() からの戻り値を格納するために使用される変数は、ローカルまたはグローバルにすることができます。新しい (promise) と古い形式の呼び出しの両方がバグを引き起こします。
4) 回避策やバグを回避する方法が見つかりません。
イアン