From a1e671ac6a42e2749e75184dee64ae43cd833aaa Mon Sep 17 00:00:00 2001 From: James Mackay Date: Thu, 8 Oct 2026 08:43:23 +0100 Subject: [PATCH] fix: track intent-retry tasks in the unload-cancelled task registry so removal can't trigger a shell() auto-reconnect (reviewer F2) --- custom_components/nvidia_shield/media_player.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/custom_components/nvidia_shield/media_player.py b/custom_components/nvidia_shield/media_player.py index 0e350b7..6d4c566 100644 --- a/custom_components/nvidia_shield/media_player.py +++ b/custom_components/nvidia_shield/media_player.py @@ -258,11 +258,11 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity): and self._adb_poller.connected ): # The command was originally served by ADB — retry over ADB. - self.hass.async_create_task( + self._track_task( self._adb_poller.send_media_command(intent.adb_command) ) else: - self.hass.async_create_task( + self._track_task( self._cmd(intent.command) ) self._intent_timer_unsub = async_call_later( @@ -377,7 +377,18 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity): @callback def _adb_poll_callback(self, _now) -> None: """Schedule the ADB poll as a tracked task (cancelled on unload).""" - task = self.hass.async_create_task(self._adb_poll()) + self._track_task(self._adb_poll()) + + def _track_task(self, coro) -> None: + """Dispatch a background task and register it for unload cancellation. + + Any fire-and-forget task that can touch the ADB poller must go through + here: a bare hass.async_create_task survives entity removal and, with + shell()'s auto-reconnect, can re-handshake the socket for a removed + entity (reviewer finding F2). Cancelation in async_will_remove_from_hass + covers poll and intent-retry tasks alike. + """ + task = self.hass.async_create_task(coro) self._adb_poll_tasks.add(task) task.add_done_callback(self._adb_poll_tasks.discard)