Ankündigung

Einklappen
Keine Ankündigung bisher.

Lösungsvorschlag : Websocket-Modul: RuntimeWarning und „Task was destroyed but it is pending!“ beim Beenden von SmartHomeNG

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Lösungsvorschlag : Websocket-Modul: RuntimeWarning und „Task was destroyed but it is pending!“ beim Beenden von SmartHomeNG

    Hallo zusammen,

    beim Beenden bzw. Neustarten von SmartHomeNG erscheinen bei mir regelmäßig folgende Meldungen:
    ​
    Code:
    ERROR  asyncio  Task was destroyed but it is pending!
    task: <Task pending name='update_all_series' coro=<Protocol.update_all_series() running at .../modules/websocket/smartvisu.py:617> ...>
    ERROR  asyncio  Task was destroyed but it is pending!
    task: <Task pending name='update_all_series' coro=<Protocol.update_all_series() running at .../modules/websocket/admin.py:576> ...>​
    und, wenn SHNG im Vordergrund unter systemd läuft (stderr im Journal):

    Code:
    modules/websocket/__init__.py:256: RuntimeWarning: coroutine 'BaseEventLoop.shutdown_asyncgens' was never awaited
      self.loop.shutdown_asyncgens()​
    Umgebung: SmartHomeNG v1.11.0-master (388aae606), Python 3.10.13, Raspberry Pi 5, Debian 12. Die Stelle ist im aktuellen master unverändert.

    Ursache (modules/websocket/__init__.py, _ws_server_thread(), finally-Block):
    1. self.loop.shutdown_asyncgens() ist eine Coroutine. Sie wird nur erzeugt, aber nie ausgeführt. Daher die RuntimeWarning, und die Async-Generatoren werden nicht aufgeräumt.
    2. Die noch laufenden Tasks (z. B. update_all_series der Protokolle smartvisu und admin) werden vor self.loop.close() nicht abgebrochen. Beim Schließen der Loop sind sie noch „pending“, daher „Task was destroyed but it is pending!“.

    Lösungsvorschlag für den finally-Block:
    ​
    Code:
            try:
                self.loop.run_forever()
            finally:
                try:
                    # noch laufende Tasks (z.B. update_all_series) sauber abbrechen
                    pending = asyncio.all_tasks(self.loop)
                    for task in pending:
                        task.cancel()
                    if pending:
                        self.loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
                    # Coroutine muss ausgefuehrt werden, nicht nur aufgerufen
                    self.loop.run_until_complete(self.loop.shutdown_asyncgens())
                except Exception as e:
                    self.logger.warning(f'_ws_server_thread: finally - Exception on shutdown: {e}')
                try:
                    self.loop.close()
                except Exception as e:
                    self.logger.warning(f'_ws_server_thread: finally - Exception on loop.close(): {e}')​
    Ich habe das Verhalten mit einem kleinen Testskript nachgestellt (Event-Loop im Thread, run_forever(), Stopp per call_soon_threadsafe(loop.stop), ein Endlos-Task und ein Async-Generator). Der bisherige Code erzeugt genau beide Meldungen, mit der Änderung gibt es keine Meldung mehr, und der Generator wird ordentlich aufgeräumt.

    Mir ist aufgefallen, dass run_until_complete(self.loop.shutdown_asyncgens()) im Code als Kommentar schon steht. Falls es einen Grund gab, das nicht zu verwenden, etwa ein Hängen beim Beenden, wäre ich für einen Hinweis dankbar.

    Die Meldungen sind harmlos, das Beenden funktioniert. Sie tauchen aber bei jedem Neustart im Warnungs-Log auf und verwirren bei der Fehlersuche.

    Vielleicht hat ja auch einer von euch Kontakt zu den Entwicklern - wäre cool.

    Viele Grüße
    ​Günther

    #2

    Das ist im aktuellen Develop bereits gefixt, zusammen mit anderen Änderungen aber danke für dein Feedback, es ist schön zu sehen, dass sich immer noch Leute finden, die sich Gedanken darum machen, shng zu verbessern

    Achso, das nächste Release kommt zeitig vor Weihnachten.

    Kommentar

    Lädt...
    X