Improve D-Bus timeout error handling (#5664)

* Improve D-Bus timeout error handling

Typically D-Bus timeouts are related to systemd activation timing out
after 25s. The current dbus-fast timeout of 10s is well below that
so we never get the actual D-Bus error. This increases the dbus-fast
timeout to 30s, which will make sure we wait long enought to get the
actual D-Bus error from the broker.

Note that this should not slow down a typical system, since we tried
three times each waiting for 10s. With the new error handling typically
we'll end up waiting 25s and then receive the actual D-Bus error. There
is no point in waiting for multiple D-Bus/systemd caused timeouts.

* Create D-Bus TimedOut exception
This commit is contained in:
Stefan Agner 2025-02-25 17:11:23 +01:00 committed by GitHub
parent 644ec45ded
commit 15e8940c7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 11 deletions

View File

@ -66,8 +66,8 @@ class UDisks2Manager(DBusInterfaceProxy):
try: try:
await super().connect(bus) await super().connect(bus)
await self.udisks2_object_manager.connect(bus) await self.udisks2_object_manager.connect(bus)
except DBusError: except DBusError as err:
_LOGGER.warning("Can't connect to udisks2") _LOGGER.critical("Can't connect to udisks2: %s", err)
except (DBusServiceUnkownError, DBusInterfaceError): except (DBusServiceUnkownError, DBusInterfaceError):
_LOGGER.warning( _LOGGER.warning(
"No udisks2 support on the host. Host control has been disabled." "No udisks2 support on the host. Host control has been disabled."

View File

@ -403,7 +403,11 @@ class DBusParseError(DBusError):
class DBusTimeoutError(DBusError): class DBusTimeoutError(DBusError):
"""D-Bus call timed out.""" """D-Bus call timeout."""
class DBusTimedOutError(DBusError):
"""D-Bus call timed out (typically when systemd D-Bus service activation fail)."""
class DBusNoReplyError(DBusError): class DBusNoReplyError(DBusError):

View File

@ -189,12 +189,13 @@ class DataDisk(CoreSysAttributes):
await self.sys_dbus.agent.datadisk.reload_device() await self.sys_dbus.agent.datadisk.reload_device()
# Register for signals on devices added/removed # Register for signals on devices added/removed
self.sys_dbus.udisks2.udisks2_object_manager.dbus.object_manager.on_interfaces_added( if self.sys_dbus.udisks2.is_connected:
self._udisks2_interface_added self.sys_dbus.udisks2.udisks2_object_manager.dbus.object_manager.on_interfaces_added(
) self._udisks2_interface_added
self.sys_dbus.udisks2.udisks2_object_manager.dbus.object_manager.on_interfaces_removed( )
self._udisks2_interface_removed self.sys_dbus.udisks2.udisks2_object_manager.dbus.object_manager.on_interfaces_removed(
) self._udisks2_interface_removed
)
@Job( @Job(
name="data_disk_migrate", name="data_disk_migrate",

View File

@ -31,6 +31,7 @@ from ..exceptions import (
DBusObjectError, DBusObjectError,
DBusParseError, DBusParseError,
DBusServiceUnkownError, DBusServiceUnkownError,
DBusTimedOutError,
DBusTimeoutError, DBusTimeoutError,
HassioNotSupportedError, HassioNotSupportedError,
) )
@ -87,6 +88,8 @@ class DBus:
return DBusNotConnectedError(err.text) return DBusNotConnectedError(err.text)
if err.type == ErrorType.TIMEOUT: if err.type == ErrorType.TIMEOUT:
return DBusTimeoutError(err.text) return DBusTimeoutError(err.text)
if err.type == ErrorType.TIMED_OUT:
return DBusTimedOutError(err.text)
if err.type == ErrorType.NO_REPLY: if err.type == ErrorType.NO_REPLY:
return DBusNoReplyError(err.text) return DBusNoReplyError(err.text)
return DBusFatalError(err.text, type_=err.type) return DBusFatalError(err.text, type_=err.type)
@ -136,7 +139,7 @@ class DBus:
for _ in range(3): for _ in range(3):
try: try:
return await self._bus.introspect( return await self._bus.introspect(
self.bus_name, self.object_path, timeout=10 self.bus_name, self.object_path, timeout=30
) )
except InvalidIntrospectionError as err: except InvalidIntrospectionError as err:
raise DBusParseError( raise DBusParseError(
@ -144,7 +147,13 @@ class DBus:
) from err ) from err
except DBusFastDBusError as err: except DBusFastDBusError as err:
raise DBus.from_dbus_error(err) from None raise DBus.from_dbus_error(err) from None
except (EOFError, TimeoutError): except TimeoutError:
# The systemd D-Bus activate service has a timeout of 25s, which will raise. We should
# not end up here unless the D-Bus broker is majorly overwhelmed.
_LOGGER.critical(
"Timeout connecting to %s - %s", self.bus_name, self.object_path
)
except EOFError:
_LOGGER.warning( _LOGGER.warning(
"Busy system at %s - %s", self.bus_name, self.object_path "Busy system at %s - %s", self.bus_name, self.object_path
) )