mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 02:05:22 -04:00
fix(cookbook): recover completed downloads from DOWNLOAD_OK in background reconciler (#4000)
The dashboard background status reconciler (_pollBackgroundStatus) only recovered "done" for dependency installs when the backend reported a finished task as "stopped". A real model download whose tmux pane is gone after DOWNLOAD_OK (so the dead-session check misses the landed snapshot) fell through to `task.type === 'download' ? 'crashed'`, so a completed download was shown as crashed (and stalled on the Serve tab). Recover "done" from the terminal DOWNLOAD_OK sentinel, mirroring the dep-install recovery already present. The background poll runs blind, so it keys off the conclusive exit-0 sentinel only — not the `/snapshots/` path, which can be printed mid-stream for multi-file downloads and would risk marking an incomplete download done. Fixes #3897 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3533,12 +3533,22 @@ async function _pollBackgroundStatus() {
|
|||||||
// dead-session check inspects). Recover "done" from the retained output's
|
// dead-session check inspects). Recover "done" from the retained output's
|
||||||
// exit-0 sentinel so a clean install isn't downgraded to crashed.
|
// exit-0 sentinel so a clean install isn't downgraded to crashed.
|
||||||
const depDone = !!task.payload?._dep && _depInstallSucceeded(task.output);
|
const depDone = !!task.payload?._dep && _depInstallSucceeded(task.output);
|
||||||
|
// A finished model download whose tmux pane is gone is also reported
|
||||||
|
// "stopped" (the dead-session check can miss the landed snapshot).
|
||||||
|
// Recover "done" from the terminal `DOWNLOAD_OK` sentinel — emitted
|
||||||
|
// only after the runner exits 0 — so a completed download isn't
|
||||||
|
// downgraded to crashed. This background poll runs blind (no live
|
||||||
|
// stream to debounce against), so unlike the reconnect loop it keys
|
||||||
|
// off the conclusive exit sentinel only, never the `/snapshots/` path,
|
||||||
|
// which can be printed mid-stream for multi-file downloads.
|
||||||
|
const downloadDone = task.type === 'download'
|
||||||
|
&& String(task.output || '').includes('DOWNLOAD_OK');
|
||||||
const nextStatus = live.status === 'completed'
|
const nextStatus = live.status === 'completed'
|
||||||
? 'done'
|
? 'done'
|
||||||
: (live.status === 'error'
|
: (live.status === 'error'
|
||||||
? 'error'
|
? 'error'
|
||||||
: (live.status === 'stopped'
|
: (live.status === 'stopped'
|
||||||
? (depDone ? 'done' : (task.type === 'download' ? 'crashed' : 'stopped'))
|
? ((depDone || downloadDone) ? 'done' : (task.type === 'download' ? 'crashed' : 'stopped'))
|
||||||
: null));
|
: null));
|
||||||
if (nextStatus && task.status !== nextStatus) {
|
if (nextStatus && task.status !== nextStatus) {
|
||||||
updates.status = nextStatus;
|
updates.status = nextStatus;
|
||||||
|
|||||||
@@ -74,7 +74,23 @@ def test_background_poll_recovers_done_for_stopped_dependency_install():
|
|||||||
source = _read("static/js/cookbookRunning.js")
|
source = _read("static/js/cookbookRunning.js")
|
||||||
|
|
||||||
assert "const depDone = !!task.payload?._dep && _depInstallSucceeded(task.output);" in source
|
assert "const depDone = !!task.payload?._dep && _depInstallSucceeded(task.output);" in source
|
||||||
assert "depDone ? 'done' : (task.type === 'download' ? 'crashed' : 'stopped')" in source
|
assert "(depDone || downloadDone) ? 'done' : (task.type === 'download' ? 'crashed' : 'stopped')" in source
|
||||||
|
|
||||||
|
|
||||||
|
def test_background_poll_recovers_done_for_completed_download():
|
||||||
|
"""When the backend reports a finished model download as "stopped" (its
|
||||||
|
tmux pane is gone after DOWNLOAD_OK, so the dead-session check can miss the
|
||||||
|
landed snapshot), the reconciler must recover "done" from the terminal
|
||||||
|
DOWNLOAD_OK sentinel instead of downgrading the card to crashed. The
|
||||||
|
background poll keys off DOWNLOAD_OK only (not the "/snapshots/" path, which
|
||||||
|
can appear mid-stream for multi-file downloads)."""
|
||||||
|
source = _read("static/js/cookbookRunning.js")
|
||||||
|
|
||||||
|
normalized = " ".join(source.split())
|
||||||
|
assert (
|
||||||
|
"const downloadDone = task.type === 'download' "
|
||||||
|
"&& String(task.output || '').includes('DOWNLOAD_OK');"
|
||||||
|
) in normalized
|
||||||
|
|
||||||
|
|
||||||
def test_dependency_install_payload_keeps_env_path_for_refresh():
|
def test_dependency_install_payload_keeps_env_path_for_refresh():
|
||||||
|
|||||||
Reference in New Issue
Block a user