From cd31dd27fd696ac3e74ad691513168f4de0fb92e Mon Sep 17 00:00:00 2001 From: zhayujie Date: Wed, 8 Apr 2026 11:48:27 +0800 Subject: [PATCH] fix: increase web console capacity and add frontend retry --- channel/web/static/js/console.js | 55 +++++++++++++++++++++----------- channel/web/web_channel.py | 8 ++++- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/channel/web/static/js/console.js b/channel/web/static/js/console.js index 7139b1c7..24e120be 100644 --- a/channel/web/static/js/console.js +++ b/channel/web/static/js/console.js @@ -763,29 +763,46 @@ function sendMessage() { })); } - fetch('/message', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(body) - }) - .then(r => r.json()) - .then(data => { - if (data.status === 'success') { - if (data.stream) { - startSSE(data.request_id, loadingEl, timestamp); + const MAX_RETRIES = 2; + const RETRY_DELAY_MS = 1000; + + function postWithRetry(attempt) { + fetch('/message', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }) + .then(r => r.json()) + .then(data => { + if (data.status === 'success') { + if (data.stream) { + startSSE(data.request_id, loadingEl, timestamp); + } else { + loadingContainers[data.request_id] = loadingEl; + if (!isPolling) startPolling(); + } } else { - loadingContainers[data.request_id] = loadingEl; - if (!isPolling) startPolling(); + loadingEl.remove(); + addBotMessage(t('error_send'), new Date()); + } + }) + .catch(err => { + if (err.name === 'AbortError') { + loadingEl.remove(); + addBotMessage(t('error_timeout'), new Date()); + return; + } + if (attempt < MAX_RETRIES) { + console.warn(`[sendMessage] attempt ${attempt + 1} failed, retrying...`, err); + setTimeout(() => postWithRetry(attempt + 1), RETRY_DELAY_MS * (attempt + 1)); + return; } - } else { loadingEl.remove(); addBotMessage(t('error_send'), new Date()); - } - }) - .catch(err => { - loadingEl.remove(); - addBotMessage(err.name === 'AbortError' ? t('error_timeout') : t('error_send'), new Date()); - }); + }); + } + + postWithRetry(0); } function startSSE(requestId, loadingEl, timestamp) { diff --git a/channel/web/web_channel.py b/channel/web/web_channel.py index ab8f7c02..32b27062 100644 --- a/channel/web/web_channel.py +++ b/channel/web/web_channel.py @@ -454,8 +454,14 @@ class WebChannel(ChatChannel): func = web.httpserver.StaticMiddleware(app.wsgifunc()) func = web.httpserver.LogMiddleware(func) server = web.httpserver.WSGIServer(("0.0.0.0", port), func) - # Allow concurrent requests by not blocking on in-flight handler threads server.daemon_threads = True + # Default request_queue_size(5) / timeout(10s) / numthreads(10) are + # too small: when SSE streams occupy many threads, the backlog fills + # and new connections get refused (ERR_CONNECTION_ABORTED). + server.request_queue_size = 128 + server.timeout = 300 + server.requests.min = 20 + server.requests.max = 80 self._http_server = server try: server.start()