diff --git a/src/app_runtime/core/runtime.py b/src/app_runtime/core/runtime.py index 28f52d0..c5f48e6 100644 --- a/src/app_runtime/core/runtime.py +++ b/src/app_runtime/core/runtime.py @@ -65,11 +65,16 @@ class RuntimeManager: if not self._started: return self._state = LifecycleState.STOPPING - self.workers.stop(timeout=timeout, force=force) - if stop_control_plane: - self.control_plane.stop() - self._started = False - self._state = LifecycleState.STOPPED + try: + self.workers.stop(timeout=timeout, force=force) + except TimeoutError: + # Do not leave runtime in STOPPING forever for control-plane callers. + self.workers.stop(force=True) + finally: + if stop_control_plane: + self.control_plane.stop() + self._started = False + self._state = LifecycleState.STOPPED def status(self) -> dict[str, object]: self._refresh_state() @@ -85,13 +90,15 @@ class RuntimeManager: async def start_runtime(self) -> str: if self._started: return "runtime already running" + if self.workers.lifecycle_state() == LifecycleState.STOPPING: + return "runtime is stopping" self.start(start_control_plane=False) return "runtime started" async def stop_runtime(self) -> str: if not self._started: return "runtime already stopped" - self.stop(stop_control_plane=False) + self.stop(timeout=0.0, stop_control_plane=False) return "runtime stopped" async def runtime_status(self) -> str: