diff --git a/supervisor/core.py b/supervisor/core.py index 0fd57985a..4ce1bb08d 100644 --- a/supervisor/core.py +++ b/supervisor/core.py @@ -315,6 +315,9 @@ class Core(CoreSysAttributes): # don't process scheduler anymore await self.set_state(CoreState.STOPPING) + # Cancel shutdown monitor task before tearing down infrastructure + await self.sys_host.unload() + # Stage 1 try: async with asyncio.timeout(10): @@ -341,7 +344,6 @@ class Core(CoreSysAttributes): self.sys_websession.close(), self.sys_ingress.unload(), self.sys_hardware.unload(), - self.sys_host.unload(), self.sys_dbus.unload(), ) ] @@ -359,7 +361,13 @@ class Core(CoreSysAttributes): Reentrant: if a shutdown is already in progress, subsequent calls await completion of the existing shutdown rather than starting a second one. """ - if self.state in (CoreState.SHUTDOWN, CoreState.STOPPING, CoreState.CLOSE): + # Supervisor is already tearing down, no point running shutdown + if self.state in (CoreState.STOPPING, CoreState.CLOSE): + _LOGGER.warning("Ignoring shutdown request, Supervisor is already stopping") + return + + # Another shutdown is in progress, wait for it to complete + if self.state == CoreState.SHUTDOWN: await self._shutdown_event.wait() return diff --git a/tests/test_core.py b/tests/test_core.py index 505574bf8..be30243e8 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -211,3 +211,19 @@ async def test_shutdown_event_reset_between_cycles(coresys: CoreSys): assert second_entered assert coresys.core._shutdown_event.is_set() + + +@pytest.mark.parametrize( + "state", [CoreState.STOPPING, CoreState.CLOSE], ids=["stopping", "close"] +) +async def test_shutdown_ignored_during_stop( + coresys: CoreSys, caplog: pytest.LogCaptureFixture, state: CoreState +): + """Test that shutdown is ignored when Supervisor is already stopping.""" + await coresys.core.set_state(state) + + with patch.object(coresys.addons, "shutdown") as mock_addon_shutdown: + await coresys.core.shutdown() + + mock_addon_shutdown.assert_not_called() + assert "Ignoring shutdown request, Supervisor is already stopping" in caplog.text