From 235d668d9f22066b4c2d94b83a34d2a294f1954c Mon Sep 17 00:00:00 2001 From: Kai Chappell Date: Thu, 29 Jan 2026 23:38:31 +0000 Subject: [PATCH] fix(dashboard): handle orphan server on Docker refresh Check port availability before singleton state to detect orphan servers from previous processes. When ports are in use but singleton is None, wait up to 5 seconds for the orphan to shut down before failing with a clear error message. Co-Authored-By: Claude Opus 4.5 --- src/py_dvt_ate/app/dashboard/app.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/py_dvt_ate/app/dashboard/app.py b/src/py_dvt_ate/app/dashboard/app.py index 7bfd933..02090f6 100644 --- a/src/py_dvt_ate/app/dashboard/app.py +++ b/src/py_dvt_ate/app/dashboard/app.py @@ -128,12 +128,31 @@ def get_or_create_server() -> SimulationServer: """ global _simulation_server, _server_thread - # Return existing server if it's running AND responsive - if _simulation_server is not None and _simulation_server.is_running: - # Verify the server is actually responding (not a stale flag) - if _is_server_responsive(): + # FIRST: Check if ports are already in use (regardless of singleton state) + # This catches orphan servers from previous processes (e.g., Docker restarts) + ports_in_use = _is_server_responsive() + + if ports_in_use: + # Ports are in use - either our singleton or an orphan process + if _simulation_server is not None and _simulation_server.is_running: + # We have a reference - reuse it return _simulation_server - # Server flag says running but it's not responsive - clean up + else: + # Orphan server from previous process - wait for it to die + st.warning("Waiting for previous server to shut down...") + for _ in range(10): # Wait up to 5 seconds + time.sleep(0.5) + if not _is_server_responsive(): + break + else: + st.error( + "Port still in use. Please wait a moment and refresh, " + "or restart the container." + ) + st.stop() + + # Clean up stale singleton reference if ports are free but singleton exists + if _simulation_server is not None and not ports_in_use: _simulation_server = None _server_thread = None