Disconnect sendspin clients to allow clean shutdown (#2887)
authorPaulus Schoutsen <balloob@gmail.com>
Fri, 2 Jan 2026 10:30:48 +0000 (11:30 +0100)
committerGitHub <noreply@github.com>
Fri, 2 Jan 2026 10:30:48 +0000 (11:30 +0100)
I was unable to do a clean shutdown in development when a Sendspin client was connected to the Sendspin server. This PR fixes it.

STR
- Start MA
- Connect sendspin client (I was using sendspin-js)
- Shut down MA using ctrl+C
- Hangs

With this PR: shuts down cleanly

music_assistant/providers/sendspin/provider.py

index 9c5028bd91c82c188e358d36c615676af495a5d8..0cde94a6bec5c1b5a61c953fc14a8845ce395486 100644 (file)
@@ -103,12 +103,23 @@ class SendspinProvider(PlayerProvider):
 
         :param is_removed: True when the provider is removed from the configuration.
         """
+        # Disconnect all clients before stopping the server
+        clients = list(self.server_api.clients)
+        disconnect_tasks = []
+        for client in clients:
+            self.logger.debug("Disconnecting client %s", client.client_id)
+            disconnect_tasks.append(client.disconnect(retry_connection=False))
+        if disconnect_tasks:
+            results = await asyncio.gather(*disconnect_tasks, return_exceptions=True)
+            for client, result in zip(clients, results, strict=True):
+                if isinstance(result, Exception):
+                    self.logger.warning(
+                        "Error disconnecting client %s: %s", client.client_id, result
+                    )
+
         # Stop the Sendspin server
         await self.server_api.close()
 
         for cb in self.unregister_cbs:
             cb()
         self.unregister_cbs = []
-        for player in self.players:
-            self.logger.debug("Unloading player %s", player.name)
-            await self.mass.players.unregister(player.player_id)