fix(kvm): treat an absent display as retryable in capture loops #121
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/VA-119-kvm-capture-retryable-absent-display"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Both long-lived KVM capture loops (the tile stream in
dispatch.rsand the native VNCmain_loopinvnc_native/server.rs) terminated on the first capture error, including the transient "display not ready" case (KvmError::NotAvailable) and the equally-transientCaptureFailed. A momentarily-absent display is normal and self-healing (early boot, a VT switch, a display-manager restart, a GPU modeset, a session teardown), so the loops died on conditions a hosting-company console rides through with a spinner.Both loops now treat
NotAvailableandCaptureFailedas retryable. On a capture error the loop enters a slow-probe state on a fixed 1000ms cadence decoupled from FPS, so it does not hammer the backend during a long outage, and resumes automatically on the next successful capture. The only remaining terminators are the cancel signal and a closed outbox (and, for VNC, a client disconnect).Tile stream: capture is split from the diff so
StreamState::invalidateruns on recovery and the first frame after a gap re-ships the whole screen. The fatalkvm_stream_errorreturn path is removed; a newkvm_stream_statusaction carryingstate("waiting"/"streaming") and the last error text is emitted only on a waiting<->streaming transition so the operator UI can show "waiting for display".run_kvm_streamis now generic over the sharedCaptureSourceso the state machine is testable with a mock.Native VNC:
main_loopcaptures before diffing and no longer returnsErron a capture failure; it holds the connection, keepspending_update, backs the frame timer off to the probe cadence, and clearssession.prevon entering waiting so recovery sends a full-framebuffer update rather than leaving the client on a stale partial frame. RFB is incremental, so the client keeps its last frame on screen through the gap.Transition logging is throttled to one line per state change (entering waiting, resuming), never per probe tick.
Tests: a mock-
CaptureSourcetile-stream test drives NotAvailable -> CaptureFailed -> Ok and asserts the loop stays alive, emits exactly one waiting and one streaming transition, re-ships a full frame on resume, and never emitskvm_stream_error. A VNCmain_looptest feeds the same failure-then-recovery sequence and asserts the connection stays open and a full-framebuffer update arrives on recovery.#VA-119
Both long-lived KVM capture loops (the tile stream in `dispatch.rs` and the native VNC `main_loop` in `vnc_native/server.rs`) terminated on the first capture error, including the transient "display not ready" case (`KvmError::NotAvailable`) and the equally-transient `CaptureFailed`. A momentarily-absent display is normal and self-healing (early boot, a VT switch, a display-manager restart, a GPU modeset, a session teardown), so the loops died on conditions a hosting-company console rides through with a spinner. Both loops now treat `NotAvailable` and `CaptureFailed` as retryable. On a capture error the loop enters a slow-probe state on a fixed 1000ms cadence decoupled from FPS, so it does not hammer the backend during a long outage, and resumes automatically on the next successful capture. The only remaining terminators are the cancel signal and a closed outbox (and, for VNC, a client disconnect). Tile stream: capture is split from the diff so `StreamState::invalidate` runs on recovery and the first frame after a gap re-ships the whole screen. The fatal `kvm_stream_error` return path is removed; a new `kvm_stream_status` action carrying `state` ("waiting"/"streaming") and the last error text is emitted only on a waiting<->streaming transition so the operator UI can show "waiting for display". `run_kvm_stream` is now generic over the shared `CaptureSource` so the state machine is testable with a mock. Native VNC: `main_loop` captures before diffing and no longer returns `Err` on a capture failure; it holds the connection, keeps `pending_update`, backs the frame timer off to the probe cadence, and clears `session.prev` on entering waiting so recovery sends a full-framebuffer update rather than leaving the client on a stale partial frame. RFB is incremental, so the client keeps its last frame on screen through the gap. Transition logging is throttled to one line per state change (entering waiting, resuming), never per probe tick. Tests: a mock-`CaptureSource` tile-stream test drives NotAvailable -> CaptureFailed -> Ok and asserts the loop stays alive, emits exactly one waiting and one streaming transition, re-ships a full frame on resume, and never emits `kvm_stream_error`. A VNC `main_loop` test feeds the same failure-then-recovery sequence and asserts the connection stays open and a full-framebuffer update arrives on recovery. #VA-119