From 5e7727475748e6e25afe10e16ead6f7fb06dc759 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 3 May 2026 10:15:53 -0400 Subject: [PATCH 1/2] feat(document): add bounded proxy status retries with transport fallback Replace the unbounded 100ms polling loop for `proxy.php` status checks with limited exponential retries. Split server-starting retries from transport failures so we can show a more specific fallback error when the built-in CODE server cannot be reached at all. This avoids indefinite waiting and improves startup robustness / user feedback for built-in server deployments. Signed-off-by: Josh --- src/document.js | 124 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 9 deletions(-) diff --git a/src/document.js b/src/document.js index 200094df94..7bd91e5769 100644 --- a/src/document.js +++ b/src/document.js @@ -38,18 +38,110 @@ if (isDirectEditing()) { } let checkingProxyStatus = false +let proxyStatusAttempts = 0 +let proxyTransportAttempts = 0 +let proxyStatusTimer = null +let proxyStatusTerminal = false + +const PROXY_STATUS_MAX_ATTEMPTS = 8 +const PROXY_STATUS_INITIAL_DELAY_MS = 250 +const PROXY_STATUS_MAX_DELAY_MS = 4000 + +const PROXY_TRANSPORT_MAX_ATTEMPTS = 3 +const PROXY_TRANSPORT_INITIAL_DELAY_MS = 500 +const PROXY_TRANSPORT_MAX_DELAY_MS = 2000 + +const setProxyLoadingMessage = (message) => { + document.getElementById('proxyLoadingIcon').classList.add('icon-loading-small') + document.getElementById('proxyLoadingMessage').textContent = message +} + +const showProxyFallbackError = () => { + setProxyLoadingMessage(t( + 'richdocuments', + 'Error: The Collabora Online Built-in server is taking too long to start. Please try again or set up a standalone server.' + )) + checkingProxyStatus = false + proxyStatusTerminal = true +} + +const showProxyTransportError = () => { + setProxyLoadingMessage(t( + 'richdocuments', + 'Error: Unable to contact the Collabora Online Built-in server. Please try again or set up a standalone server.' + )) + checkingProxyStatus = false + proxyStatusTerminal = true +} + +const scheduleProxyStatusRetry = () => { + if (proxyStatusTerminal) { + return + } + + if (proxyStatusAttempts >= PROXY_STATUS_MAX_ATTEMPTS) { + showProxyFallbackError() + return + } + + const delay = Math.min( + PROXY_STATUS_INITIAL_DELAY_MS * Math.pow(2, proxyStatusAttempts), + PROXY_STATUS_MAX_DELAY_MS + ) + + proxyStatusAttempts++ + clearTimeout(proxyStatusTimer) + proxyStatusTimer = setTimeout(function() { + checkProxyStatus() + }, delay) +} + +const scheduleProxyTransportRetry = () => { + if (proxyStatusTerminal) { + return + } + + if (proxyTransportAttempts >= PROXY_TRANSPORT_MAX_ATTEMPTS) { + showProxyTransportError() + return + } + + const delay = Math.min( + PROXY_TRANSPORT_INITIAL_DELAY_MS * Math.pow(2, proxyTransportAttempts), + PROXY_TRANSPORT_MAX_DELAY_MS + ) + + proxyTransportAttempts++ + clearTimeout(proxyStatusTimer) + proxyStatusTimer = setTimeout(function() { + checkProxyStatus() + }, delay) +} const checkProxyStatus = () => { + if (proxyStatusTerminal) { + return + } checkingProxyStatus = true const url = Config.get('urlsrc').slice(0, Config.get('urlsrc').indexOf('proxy.php') + 'proxy.php'.length) - $.get(url + '?status').done(function(val) { + + $.ajax({ + url: url + '?status', + method: 'GET', + dataType: 'json', + timeout: 5000, + }).done(function(val) { + if (proxyStatusTerminal) { + return + } + + proxyTransportAttempts = 0 + if (val && val.status && val.status !== 'OK') { if (val.status === 'starting' || val.status === 'stopped') { - document.getElementById('proxyLoadingIcon').classList.add('icon-loading-small') - document.getElementById('proxyLoadingMessage').textContent = t('richdocuments', 'Built-in CODE Server is starting up shortly, please wait.') + setProxyLoadingMessage(t('richdocuments', 'Built-in CODE Server is starting up shortly, please wait.')) } else if (val.status === 'restarting') { - document.getElementById('proxyLoadingIcon').classList.add('icon-loading-small') - document.getElementById('proxyLoadingMessage').textContent = t('richdocuments', 'Built-in CODE Server is restarting, please wait.') + setProxyLoadingMessage(t('richdocuments', 'Built-in CODE Server is restarting, please wait.')) } else if (val.status === 'error') { if (val.error === 'appimage_missing') { document.getElementById('proxyLoadingMessage').textContent = t('richdocuments', 'Error: Cannot find the AppImage, please reinstall the Collabora Online Built-in server.') @@ -67,20 +159,34 @@ const checkProxyStatus = () => { document.getElementById('proxyLoadingMessage').textContent = t('richdocuments', 'Error: Cannot start the Collabora Online Built-in server, please setup a standalone one.') } - // probably not even worth re-trying + checkingProxyStatus = false + proxyStatusTerminal = true return } - // retry... - setTimeout(function() { checkProxyStatus() }, 100) + // retry while the server is starting/restarting + scheduleProxyStatusRetry() return } checkingProxyStatus = false + proxyStatusTerminal = true + clearTimeout(proxyStatusTimer) + }).fail(function() { + if (proxyStatusTerminal) { + return + } + + scheduleProxyTransportRetry() }) } const showLoadingIndicator = () => { + proxyStatusAttempts = 0 + proxyTransportAttempts = 0 + proxyStatusTerminal = false + clearTimeout(proxyStatusTimer) + if ((OC.appswebroots.richdocumentscode || OC.appswebroots.richdocumentscode_arm64) && Config.get('urlsrc').indexOf('proxy.php') >= 0) { checkProxyStatus() } else { @@ -89,7 +195,7 @@ const showLoadingIndicator = () => { } const hideLoadingIndicator = () => { - if (checkingProxyStatus) { + if (checkingProxyStatus && !proxyStatusTerminal) { setTimeout(function() { hideLoadingIndicator() }, 100) return } From 2ae669200d7a5e448dbf85eef6cc6939e93ad365 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 3 May 2026 10:54:07 -0400 Subject: [PATCH 2/2] chore(document): fixup for lint happiness Signed-off-by: Josh --- src/document.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/document.js b/src/document.js index 7bd91e5769..bbb57c8e59 100644 --- a/src/document.js +++ b/src/document.js @@ -59,7 +59,7 @@ const setProxyLoadingMessage = (message) => { const showProxyFallbackError = () => { setProxyLoadingMessage(t( 'richdocuments', - 'Error: The Collabora Online Built-in server is taking too long to start. Please try again or set up a standalone server.' + 'Error: The Collabora Online Built-in server is taking too long to start. Please try again or set up a standalone server.', )) checkingProxyStatus = false proxyStatusTerminal = true @@ -68,7 +68,7 @@ const showProxyFallbackError = () => { const showProxyTransportError = () => { setProxyLoadingMessage(t( 'richdocuments', - 'Error: Unable to contact the Collabora Online Built-in server. Please try again or set up a standalone server.' + 'Error: Unable to contact the Collabora Online Built-in server. Please try again or set up a standalone server.', )) checkingProxyStatus = false proxyStatusTerminal = true @@ -86,7 +86,7 @@ const scheduleProxyStatusRetry = () => { const delay = Math.min( PROXY_STATUS_INITIAL_DELAY_MS * Math.pow(2, proxyStatusAttempts), - PROXY_STATUS_MAX_DELAY_MS + PROXY_STATUS_MAX_DELAY_MS, ) proxyStatusAttempts++ @@ -108,7 +108,7 @@ const scheduleProxyTransportRetry = () => { const delay = Math.min( PROXY_TRANSPORT_INITIAL_DELAY_MS * Math.pow(2, proxyTransportAttempts), - PROXY_TRANSPORT_MAX_DELAY_MS + PROXY_TRANSPORT_MAX_DELAY_MS, ) proxyTransportAttempts++ @@ -124,7 +124,7 @@ const checkProxyStatus = () => { } checkingProxyStatus = true const url = Config.get('urlsrc').slice(0, Config.get('urlsrc').indexOf('proxy.php') + 'proxy.php'.length) - + $.ajax({ url: url + '?status', method: 'GET',