core (main, xmpp): fix cleaning methods:
Cleaning methods per-profile (`profile_disconnected`) and per-plugin (`unload`) were not called correctly. They are now called on shutdown with the `before/shutdown` Twisted event. With this event, it's still possible to call Deferred and do cleaning requiring async calls. rel 479
This commit is contained in:
parent
a539c21f9d
commit
e05c69267d
2 changed files with 40 additions and 23 deletions
|
|
@ -30,10 +30,7 @@ from libervia.backend.core.i18n import _, D_, language_switch
|
|||
from libervia.backend.core import patches
|
||||
from libervia.backend.models.tor import TorData
|
||||
from libervia.backend.tools.config import (
|
||||
BridgeSettings,
|
||||
ComponentSettings,
|
||||
DBusBridgeSettings,
|
||||
PbBridgeSettings,
|
||||
)
|
||||
|
||||
patches.apply()
|
||||
|
|
@ -111,6 +108,14 @@ class LiberviaBackend(service.Service):
|
|||
# reactor is run later.
|
||||
reactor.callLater(0, self._post_init)
|
||||
|
||||
# before/shutdown event is called on backend shutdown, when it's still possible to
|
||||
# call Deferred. it's used to call all cleaning methods (per-profile's
|
||||
# "profile_disconnected", and per-plugin's "unload").
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "shutdown", lambda: defer.ensureDeferred(self._on_shutdown())
|
||||
)
|
||||
log.info("Shutdown trigger registered.")
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""Return the short version of Libervia"""
|
||||
|
|
@ -310,8 +315,7 @@ class LiberviaBackend(service.Service):
|
|||
await async_process.run(str(init_script), verbose=True)
|
||||
except RuntimeError as e:
|
||||
log.error(f"Init script failed: {e}")
|
||||
self.stopService()
|
||||
sys.exit(C.EXIT_ERROR)
|
||||
self.stop(C.EXIT_ERROR)
|
||||
|
||||
await self._sync_components_profiles()
|
||||
|
||||
|
|
@ -536,14 +540,17 @@ class LiberviaBackend(service.Service):
|
|||
self.plugins[import_name]._info = plugin_info
|
||||
# TODO: test xmppclient presence and register handler parent
|
||||
|
||||
def plugins_unload(self):
|
||||
"""Call unload method on every loaded plugin, if exists
|
||||
async def plugins_unload(self) -> None:
|
||||
"""Call ``unload`` method (if any) on every loaded plugin.
|
||||
|
||||
@return (D): A deferred which return None when all method have been called
|
||||
Unloaded plugins are removed them from self.plugins, so ``unload`` is not called
|
||||
twice.
|
||||
"""
|
||||
# TODO: in the futur, it should be possible to hot unload a plugin
|
||||
# pluging depending on the unloaded one should be unloaded too
|
||||
# for now, just a basic call on plugin.unload is done
|
||||
# TODO: in the futur, it should be possible to hot unload a plugin.
|
||||
# Plugins depending on the unloaded one should be unloaded too; for now,
|
||||
# just a basic call on plugin.unload is done.
|
||||
if not self.plugins:
|
||||
return
|
||||
defers_list = []
|
||||
for plugin in self.plugins.values():
|
||||
try:
|
||||
|
|
@ -552,7 +559,8 @@ class LiberviaBackend(service.Service):
|
|||
continue
|
||||
else:
|
||||
defers_list.append(utils.as_deferred(unload))
|
||||
return defer.DeferredList(defers_list)
|
||||
await defer.DeferredList(defers_list)
|
||||
self.plugins.clear()
|
||||
|
||||
async def _sync_components_profiles(self) -> None:
|
||||
"""Synchronize components profiles data with settings.
|
||||
|
|
@ -805,17 +813,25 @@ class LiberviaBackend(service.Service):
|
|||
self._init()
|
||||
log.info("Salut à toi ô mon frère !")
|
||||
|
||||
def stopService(self):
|
||||
async def _on_shutdown(self) -> None:
|
||||
"""Clean up resources on shutdown.
|
||||
|
||||
Disconnect all profiles first so profile_disconnected callbacks fire, then unload
|
||||
plugins and storage.
|
||||
"""
|
||||
if self.local_shared_path is not None:
|
||||
log.debug("Cleaning shared temporary dir.")
|
||||
shutil.rmtree(self.local_shared_path, ignore_errors=True)
|
||||
log.info("Salut aussi à Rantanplan.")
|
||||
|
||||
return defer.DeferredList([self.plugins_unload(), G.storage.unload()])
|
||||
|
||||
def run(self):
|
||||
log.debug(_("running app"))
|
||||
reactor.run()
|
||||
disconnect_defers = [
|
||||
client.entity_disconnect()
|
||||
for client in self.profiles.values()
|
||||
if client.is_connected()
|
||||
]
|
||||
if disconnect_defers:
|
||||
await defer.DeferredList(disconnect_defers)
|
||||
await self.plugins_unload()
|
||||
await G.storage.unload()
|
||||
|
||||
def stop(self, exit_code: int | None = None):
|
||||
log.debug(_("stopping app"))
|
||||
|
|
|
|||
|
|
@ -546,7 +546,9 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
|
|||
# the following Deferred is used to know when we are connected
|
||||
# so we need to be set it to None when connection is lost
|
||||
self._connected_d = defer.Deferred()
|
||||
self._connected_d.addCallback(self._clean_connection)
|
||||
self._connected_d.addCallback(
|
||||
lambda __: defer.ensureDeferred(self._clean_connection())
|
||||
)
|
||||
self._connected_d.addCallback(self._disconnection_cb)
|
||||
self._connected_d.addErrback(self._disconnection_eb)
|
||||
|
||||
|
|
@ -706,8 +708,7 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
|
|||
return
|
||||
self.disconnect_profile(reason)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _clean_connection(self, __):
|
||||
async def _clean_connection(self):
|
||||
"""method called on disconnection
|
||||
|
||||
used to call profile_disconnected* triggers
|
||||
|
|
@ -716,7 +717,7 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
|
|||
for plugin in self._get_plugins_list():
|
||||
disconnected_cb = getattr(plugin, trigger_name, None)
|
||||
if disconnected_cb is not None:
|
||||
yield disconnected_cb(self)
|
||||
await utils.as_deferred(disconnected_cb, self)
|
||||
|
||||
def is_connected(self) -> bool:
|
||||
"""Return True is client is fully connected
|
||||
|
|
|
|||
Loading…
Reference in a new issue