fix(container-list): report user-stopped apps as stopped despite live UI companion
A user-stopped backend (electrumx, bitcoin, lnd, fedimint) kept reading 'running' in container-list because its UI companion (electrs-ui, …) still serves the launch port, and the state-refresh upgrades any reachable launch port to 'running'. The gate's wait_for_container_status <app> stopped therefore never saw 'stopped'. Fix: load the user_stopped marker in handle_container_list and force 'stopped' for those apps before the launch-port refresh. The reconcile guard keeps the backend down, so the marker is authoritative. package.start clears it first, so a started app reports 'running' normally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
760a32bccf
commit
6e49ce6f88
@ -171,6 +171,13 @@ impl RpcHandler {
|
|||||||
// than the WebSocket-delivered package_data, which caused apps to flicker
|
// than the WebSocket-delivered package_data, which caused apps to flicker
|
||||||
// between "installed" and "not-installed" in the UI.
|
// between "installed" and "not-installed" in the UI.
|
||||||
let (data, _) = self.state_manager.get_snapshot().await;
|
let (data, _) = self.state_manager.get_snapshot().await;
|
||||||
|
// Apps the user explicitly stopped must read as "stopped" even though a
|
||||||
|
// UI companion (electrs-ui, bitcoin-ui, …) keeps serving the launch port:
|
||||||
|
// launch_port_reachable() below would otherwise upgrade an exited backend
|
||||||
|
// back to "running". The reconcile guard keeps these backends down, so the
|
||||||
|
// marker is authoritative here.
|
||||||
|
let user_stopped =
|
||||||
|
crate::crash_recovery::load_user_stopped(&self.config.data_dir).await;
|
||||||
if data.server_info.status_info.containers_scanned && !data.package_data.is_empty() {
|
if data.server_info.status_info.containers_scanned && !data.package_data.is_empty() {
|
||||||
let mut containers = Vec::with_capacity(data.package_data.len());
|
let mut containers = Vec::with_capacity(data.package_data.len());
|
||||||
for (id, pkg) in &data.package_data {
|
for (id, pkg) in &data.package_data {
|
||||||
@ -202,7 +209,11 @@ impl RpcHandler {
|
|||||||
// Scanner backoff preserves cached package_data. Refresh stable
|
// Scanner backoff preserves cached package_data. Refresh stable
|
||||||
// states so callers do not see stale `running`/`exited` after
|
// states so callers do not see stale `running`/`exited` after
|
||||||
// health-monitor recovery or Quadlet --rm container removal.
|
// health-monitor recovery or Quadlet --rm container removal.
|
||||||
if state == "running" && requires_launch_port_for_health(id) {
|
if user_stopped.contains(id) {
|
||||||
|
// User stopped it → authoritative "stopped". Do NOT let a
|
||||||
|
// still-running UI companion's launch port mark it running.
|
||||||
|
state = "stopped".to_string();
|
||||||
|
} else if state == "running" && requires_launch_port_for_health(id) {
|
||||||
if !self.cached_reachable_health(id).await?.is_some() {
|
if !self.cached_reachable_health(id).await?.is_some() {
|
||||||
state = live_state_for_app(id)
|
state = live_state_for_app(id)
|
||||||
.await
|
.await
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user