Răsfoiți Sursa

Fix idle timeout manager called from thread without event loop

When connect_device() runs via asyncio.to_thread(), it's in a separate
thread without an event loop. The idle_timeout_manager.start_idle_timeout()
was calling asyncio.create_task() which requires a running loop.

Now handles this by using asyncio.run_coroutine_threadsafe() to schedule
the timeout handler on the main event loop when called from a thread.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris 15 ore în urmă
părinte
comite
2f5ed2d90b
1 a modificat fișierele cu 21 adăugiri și 3 ștergeri
  1. 21 3
      modules/led/idle_timeout_manager.py

+ 21 - 3
modules/led/idle_timeout_manager.py

@@ -42,9 +42,27 @@ class IdleTimeoutManager:
         logger.info(f"Starting idle LED timeout: {timeout_minutes} minutes")
 
         # Create background task to handle timeout
-        self._timeout_task = asyncio.create_task(
-            self._timeout_handler(timeout_minutes, state, check_idle_callback)
-        )
+        # Handle being called from a thread without an event loop (e.g., via asyncio.to_thread)
+        try:
+            loop = asyncio.get_running_loop()
+            self._timeout_task = loop.create_task(
+                self._timeout_handler(timeout_minutes, state, check_idle_callback)
+            )
+        except RuntimeError:
+            # No running event loop in this thread - try to get the main loop
+            try:
+                loop = asyncio.get_event_loop()
+                if loop.is_running():
+                    # Schedule on the running loop from another thread
+                    asyncio.run_coroutine_threadsafe(
+                        self._timeout_handler(timeout_minutes, state, check_idle_callback),
+                        loop
+                    )
+                    logger.debug("Scheduled idle timeout on main event loop from thread")
+                else:
+                    logger.warning("Event loop exists but not running, cannot start idle timeout")
+            except Exception as e:
+                logger.warning(f"Could not start idle timeout: {e}")
 
     async def _timeout_handler(self, timeout_minutes: float, state, check_idle_callback):
         """