fix(desktop): pollSession retries with backoff before giving up
When the phone goes to background, JS is paused and HTTP keepalive connections die. On return, the first poll's fetch can hit "Failed to fetch" because of a stale connection / DNS / TLS state. The original code showed an error immediately on a single failure. Now: same polling loop tolerates up to 5 consecutive errors with exponential backoff (1s, 2s, 4s, 8s) before surfacing showError. Any successful poll resets the error counter. This rides through the typical 1-3 second post-resume blip without any user-visible failure. Pairs with the earlier WS auto-reconnect + visibilitychange handler (both bridge channels — WS and HTTP polling — now recover cleanly). Bump app.js?v=87 -> 88.
This commit is contained in:
1 parent
633e8111a8
commit
cace868fc9
2 files changed
+26
-12
No files matched your search
@@ -1948,19 +1948,33 @@ async function pollSession(sess) {
|
||||
const r = rt(sess);
|
||||
if (r.polling) return;
|
||||
r.polling = true;
|
||||
/* 手机切后台再回前台时,第一拍 fetch 经常用着死连接秒挂(Failed to fetch),
|
||||
但只要给链路 1-2 秒重建,后续就稳。原版一炸就 showError,体验糟。
|
||||
改成:同一次 polling 循环里连续失败 ≥ MAX_ERRORS 次才放弃,
|
||||
单次失败做指数退避(1s / 2s / 4s / 8s),够 ride through 一次后台恢复抖动。 */
|
||||
const MAX_ERRORS = 5;
|
||||
let consecutiveErrors = 0;
|
||||
try {
|
||||
do {
|
||||
const res = await window.ga.pollSession(sess.bridgeSessionId || sess.id, r.lastId || 0);
|
||||
if (res?.error) throw new Error(res.error.message || res.error);
|
||||
const result = res.result || res;
|
||||
for (const msg of (result.messages || [])) upsert(sess, msg, false);
|
||||
if (result.partial) upsert(sess, result.partial, true);
|
||||
const busy = result.status === 'running' || !!result.partial;
|
||||
setBusy(sess, busy);
|
||||
if (busy) await new Promise(z => setTimeout(z, 500));
|
||||
else {
|
||||
if (r.draftEl) { r.draftEl.remove(); r.draftEl = null; r.draftText = ''; }
|
||||
break;
|
||||
try {
|
||||
const res = await window.ga.pollSession(sess.bridgeSessionId || sess.id, r.lastId || 0);
|
||||
if (res?.error) throw new Error(res.error.message || res.error);
|
||||
consecutiveErrors = 0;
|
||||
const result = res.result || res;
|
||||
for (const msg of (result.messages || [])) upsert(sess, msg, false);
|
||||
if (result.partial) upsert(sess, result.partial, true);
|
||||
const busy = result.status === 'running' || !!result.partial;
|
||||
setBusy(sess, busy);
|
||||
if (busy) await new Promise(z => setTimeout(z, 500));
|
||||
else {
|
||||
if (r.draftEl) { r.draftEl.remove(); r.draftEl = null; r.draftText = ''; }
|
||||
break;
|
||||
}
|
||||
} catch (innerErr) {
|
||||
consecutiveErrors++;
|
||||
if (consecutiveErrors >= MAX_ERRORS) throw innerErr;
|
||||
const backoff = Math.min(8000, 1000 * Math.pow(2, consecutiveErrors - 1));
|
||||
await new Promise(z => setTimeout(z, backoff));
|
||||
}
|
||||
} while (true);
|
||||
} catch (e) {
|
||||
|
||||
@@ -569,6 +569,6 @@
|
||||
<!-- highlight.js -->
|
||||
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" crossorigin="anonymous"></script>
|
||||
<script src="phosphor-icons.js"></script>
|
||||
<script src="app.js?v=87"></script>
|
||||
<script src="app.js?v=88"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user