bridge (dbus): Add time out on connection:
- Add a 5s timeout on connection to avoid infinite hang when socket is not working. - Raise `BridgeInitError` on time-out (needed to make `auto` bridge fallback correctly).
This commit is contained in:
parent
25f1aa9178
commit
c6ea6ea27b
4 changed files with 100 additions and 8 deletions
|
|
@ -36,6 +36,7 @@ const_ERROR_PREFIX = const_INT_PREFIX + ".error"
|
||||||
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
||||||
const_CORE_SUFFIX = ".core"
|
const_CORE_SUFFIX = ".core"
|
||||||
const_PLUGIN_SUFFIX = ".plugin"
|
const_PLUGIN_SUFFIX = ".plugin"
|
||||||
|
const_CONNECT_TIMEOUT = 5
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
|
|
@ -123,7 +124,23 @@ class bridge:
|
||||||
|
|
||||||
async def post_init(self):
|
async def post_init(self):
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor)
|
d = client.connect(reactor)
|
||||||
|
reactor.callLater(const_CONNECT_TIMEOUT, d.cancel)
|
||||||
|
|
||||||
|
def on_cancel(failure):
|
||||||
|
if failure.check(defer.CancelledError):
|
||||||
|
log.error(
|
||||||
|
f"D-Bus connection timed out after {const_CONNECT_TIMEOUT} s, "
|
||||||
|
"please check the D-Bus service"
|
||||||
|
)
|
||||||
|
return failure
|
||||||
|
|
||||||
|
d.addErrback(on_cancel)
|
||||||
|
self.conn = await d
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except error.DBusException as e:
|
except error.DBusException as e:
|
||||||
if e.errName == "org.freedesktop.DBus.Error.NotSupported":
|
if e.errName == "org.freedesktop.DBus.Error.NotSupported":
|
||||||
log.error(
|
log.error(
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import defer, reactor
|
||||||
from txdbus import client
|
from txdbus import client
|
||||||
|
|
||||||
from .bridge_frontend import BridgeException
|
from .bridge_frontend import BridgeException
|
||||||
|
|
@ -40,6 +40,27 @@ const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
||||||
const_CORE_SUFFIX = ".core"
|
const_CORE_SUFFIX = ".core"
|
||||||
const_PLUGIN_SUFFIX = ".plugin"
|
const_PLUGIN_SUFFIX = ".plugin"
|
||||||
const_TIMEOUT = 120
|
const_TIMEOUT = 120
|
||||||
|
const_CONNECT_TIMEOUT = 5
|
||||||
|
|
||||||
|
|
||||||
|
def _connect_dbus():
|
||||||
|
"""Connect to the D-Bus session bus with a timeout.
|
||||||
|
|
||||||
|
@return: Deferred to the D-Bus connection
|
||||||
|
"""
|
||||||
|
d = client.connect(reactor)
|
||||||
|
reactor.callLater(const_CONNECT_TIMEOUT, d.cancel)
|
||||||
|
|
||||||
|
def on_cancel(failure):
|
||||||
|
if failure.check(defer.CancelledError):
|
||||||
|
log.error(
|
||||||
|
f"D-Bus connection timed out after {const_CONNECT_TIMEOUT} s, "
|
||||||
|
"please check the D-Bus service"
|
||||||
|
)
|
||||||
|
return failure
|
||||||
|
|
||||||
|
d.addErrback(on_cancel)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def dbus_to_bridge_exception(failure):
|
def dbus_to_bridge_exception(failure):
|
||||||
|
|
@ -192,7 +213,7 @@ class bridge:
|
||||||
async def bridge_connect(self) -> None:
|
async def bridge_connect(self) -> None:
|
||||||
"""Connect to the D-Bus bridge."""
|
"""Connect to the D-Bus bridge."""
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor)
|
self.conn = await _connect_dbus()
|
||||||
self.db_object = await self.conn.getRemoteObject(
|
self.db_object = await self.conn.getRemoteObject(
|
||||||
const_INT_PREFIX, const_OBJ_PATH
|
const_INT_PREFIX, const_OBJ_PATH
|
||||||
)
|
)
|
||||||
|
|
@ -218,6 +239,10 @@ class bridge:
|
||||||
)
|
)
|
||||||
except BridgeInitError as e:
|
except BridgeInitError as e:
|
||||||
raise e
|
raise e
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
if (
|
if (
|
||||||
|
|
@ -281,7 +306,7 @@ class AIOBridge(bridge):
|
||||||
async def bridge_connect(self):
|
async def bridge_connect(self):
|
||||||
"""Connect to the D-Bus bridge (async version)."""
|
"""Connect to the D-Bus bridge (async version)."""
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor).asFuture(asyncio.get_event_loop())
|
self.conn = await _connect_dbus().asFuture(asyncio.get_event_loop())
|
||||||
self.db_object = await self.conn.getRemoteObject(
|
self.db_object = await self.conn.getRemoteObject(
|
||||||
const_INT_PREFIX, const_OBJ_PATH
|
const_INT_PREFIX, const_OBJ_PATH
|
||||||
).asFuture(asyncio.get_event_loop())
|
).asFuture(asyncio.get_event_loop())
|
||||||
|
|
@ -308,6 +333,10 @@ class AIOBridge(bridge):
|
||||||
)
|
)
|
||||||
except BridgeInitError as e:
|
except BridgeInitError as e:
|
||||||
raise e
|
raise e
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ const_ERROR_PREFIX = const_INT_PREFIX + ".error"
|
||||||
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
||||||
const_CORE_SUFFIX = ".core"
|
const_CORE_SUFFIX = ".core"
|
||||||
const_PLUGIN_SUFFIX = ".plugin"
|
const_PLUGIN_SUFFIX = ".plugin"
|
||||||
|
const_CONNECT_TIMEOUT = 5
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
|
|
@ -571,7 +572,23 @@ class bridge:
|
||||||
|
|
||||||
async def post_init(self):
|
async def post_init(self):
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor)
|
d = client.connect(reactor)
|
||||||
|
reactor.callLater(const_CONNECT_TIMEOUT, d.cancel)
|
||||||
|
|
||||||
|
def on_cancel(failure):
|
||||||
|
if failure.check(defer.CancelledError):
|
||||||
|
log.error(
|
||||||
|
f"D-Bus connection timed out after {const_CONNECT_TIMEOUT} s, "
|
||||||
|
"please check the D-Bus service"
|
||||||
|
)
|
||||||
|
return failure
|
||||||
|
|
||||||
|
d.addErrback(on_cancel)
|
||||||
|
self.conn = await d
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except error.DBusException as e:
|
except error.DBusException as e:
|
||||||
if e.errName == "org.freedesktop.DBus.Error.NotSupported":
|
if e.errName == "org.freedesktop.DBus.Error.NotSupported":
|
||||||
log.error(
|
log.error(
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import defer, reactor
|
||||||
from txdbus import client
|
from txdbus import client
|
||||||
|
|
||||||
from .bridge_frontend import BridgeException
|
from .bridge_frontend import BridgeException
|
||||||
|
|
@ -40,6 +40,27 @@ const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
||||||
const_CORE_SUFFIX = ".core"
|
const_CORE_SUFFIX = ".core"
|
||||||
const_PLUGIN_SUFFIX = ".plugin"
|
const_PLUGIN_SUFFIX = ".plugin"
|
||||||
const_TIMEOUT = 120
|
const_TIMEOUT = 120
|
||||||
|
const_CONNECT_TIMEOUT = 5
|
||||||
|
|
||||||
|
|
||||||
|
def _connect_dbus():
|
||||||
|
"""Connect to the D-Bus session bus with a timeout.
|
||||||
|
|
||||||
|
@return: Deferred to the D-Bus connection
|
||||||
|
"""
|
||||||
|
d = client.connect(reactor)
|
||||||
|
reactor.callLater(const_CONNECT_TIMEOUT, d.cancel)
|
||||||
|
|
||||||
|
def on_cancel(failure):
|
||||||
|
if failure.check(defer.CancelledError):
|
||||||
|
log.error(
|
||||||
|
f"D-Bus connection timed out after {const_CONNECT_TIMEOUT} s, "
|
||||||
|
"please check the D-Bus service"
|
||||||
|
)
|
||||||
|
return failure
|
||||||
|
|
||||||
|
d.addErrback(on_cancel)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def dbus_to_bridge_exception(failure):
|
def dbus_to_bridge_exception(failure):
|
||||||
|
|
@ -192,7 +213,7 @@ class bridge:
|
||||||
async def bridge_connect(self) -> None:
|
async def bridge_connect(self) -> None:
|
||||||
"""Connect to the D-Bus bridge."""
|
"""Connect to the D-Bus bridge."""
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor)
|
self.conn = await _connect_dbus()
|
||||||
self.db_object = await self.conn.getRemoteObject(
|
self.db_object = await self.conn.getRemoteObject(
|
||||||
const_INT_PREFIX, const_OBJ_PATH
|
const_INT_PREFIX, const_OBJ_PATH
|
||||||
)
|
)
|
||||||
|
|
@ -218,6 +239,10 @@ class bridge:
|
||||||
)
|
)
|
||||||
except BridgeInitError as e:
|
except BridgeInitError as e:
|
||||||
raise e
|
raise e
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
if (
|
if (
|
||||||
|
|
@ -963,7 +988,7 @@ class AIOBridge(bridge):
|
||||||
async def bridge_connect(self):
|
async def bridge_connect(self):
|
||||||
"""Connect to the D-Bus bridge (async version)."""
|
"""Connect to the D-Bus bridge (async version)."""
|
||||||
try:
|
try:
|
||||||
self.conn = await client.connect(reactor).asFuture(asyncio.get_event_loop())
|
self.conn = await _connect_dbus().asFuture(asyncio.get_event_loop())
|
||||||
self.db_object = await self.conn.getRemoteObject(
|
self.db_object = await self.conn.getRemoteObject(
|
||||||
const_INT_PREFIX, const_OBJ_PATH
|
const_INT_PREFIX, const_OBJ_PATH
|
||||||
).asFuture(asyncio.get_event_loop())
|
).asFuture(asyncio.get_event_loop())
|
||||||
|
|
@ -990,6 +1015,10 @@ class AIOBridge(bridge):
|
||||||
)
|
)
|
||||||
except BridgeInitError as e:
|
except BridgeInitError as e:
|
||||||
raise e
|
raise e
|
||||||
|
except defer.CancelledError:
|
||||||
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
||||||
|
# so that the "auto" bridge can fall back to the next one.
|
||||||
|
raise BridgeInitError from None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue