mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-05 14:55:08 +00:00
feat(web): a start that waits for the display answers 202 and is delivered in the background
The start route held a request open for up to 45 s while a cold-started display loaded its plugins; the MQTT bridge (15 s timeout) and browsers reported a failure for a request that was then delivered. Now, when no display is listening, the route starts the service if asked and answers 202 with status "starting" at once. A single worker in the web process (web_interface/on_demand_dispatch.py) sends the request until the display acknowledges it or the wait runs out (45 s cold start, 10 s for a running service without a socket yet). A newer start supersedes the pending one; a stop cancels it (and succeeds, with cancelled_request_id, even with no display listening). The outcome is reported by /display/on-demand/status (source "web": starting, or error with start-timeout or the socket's reason, until the display publishes something newer) and by /display/current-status as on_demand_pending. Callers: the web UI's on-demand modal and "Preview on display" treat "starting" as taken (an info toast); the MQTT bridge already treats any non-error 2xx as success (now pinned by a test). Tests: the dispatcher (ack, retry then ack, start-timeout, other failures, superseded, an in-flight ack for a superseded start, stop while pending, a per-start wait, outcome lifetime); the routes (202, status routes while pending and after a timeout, a later display state replacing the failure, stop while pending, a new start superseding); a JS suite for app.js. Mutation check: 20 mutants on the worker, the routes and app.js, 20 killed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -356,9 +356,12 @@ window.previewPluginNow = function(pluginId) {
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
// 'starting' (202): the display service is starting and the request
|
||||
// follows once it listens.
|
||||
const starting = data.status === 'starting';
|
||||
showNotification(data.message || ('Previewing ' + pluginId + ' for 60 seconds'),
|
||||
data.status || 'success');
|
||||
if (data.status === 'success') window.toggleFloatingPreview(true);
|
||||
starting ? 'info' : (data.status || 'success'));
|
||||
if (data.status === 'success' || starting) window.toggleFloatingPreview(true);
|
||||
})
|
||||
.catch(err => {
|
||||
showNotification('Preview failed: ' + err.message, 'error');
|
||||
|
||||
@@ -1739,6 +1739,13 @@ function submitOnDemandRequest(event) {
|
||||
showNotification(`Requested on-demand mode for ${pluginName}`, 'success');
|
||||
closeOnDemandModal();
|
||||
setTimeout(() => loadOnDemandStatus(true), 700);
|
||||
} else if (result.status === 'starting') {
|
||||
// 202: the display service is starting; the web process sends
|
||||
// the request once it listens. The status card shows the outcome.
|
||||
const pluginName = resolvePluginDisplayName(currentOnDemandPluginId);
|
||||
showNotification(`Starting the display for ${pluginName}…`, 'info');
|
||||
closeOnDemandModal();
|
||||
setTimeout(() => loadOnDemandStatus(true), 700);
|
||||
} else {
|
||||
console.error('[submitOnDemandRequest] Request failed:', result);
|
||||
showNotification(result.message || 'Failed to start on-demand mode', 'error');
|
||||
|
||||
Reference in New Issue
Block a user