THRIFT-792: Preserve last connect exception
Preserves the last exception when TSocket connect fails to provide more
context to callers. The exceptions are already logged at info level, but
callers may suppress that or want to view details in the exception, so
attach the last as an inner layer of TTransportException, similar to
gaierror above.
diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py
index 327dae0..360b7b1 100644
--- a/lib/py/src/transport/TSocket.py
+++ b/lib/py/src/transport/TSocket.py
@@ -133,6 +133,8 @@
msg = 'failed to resolve sockaddr for ' + str(self._address)
logger.exception(msg)
raise TTransportException(type=TTransportException.NOT_OPEN, message=msg, inner=gai)
+ # Preserve the last exception to report if all addresses fail.
+ last_exc = None
for family, socktype, _, _, sockaddr in addrs:
handle = self._do_open(family, socktype)
@@ -145,13 +147,14 @@
handle.connect(sockaddr)
self.handle = handle
return
- except socket.error:
+ except socket.error as e:
handle.close()
logger.info('Could not connect to %s', sockaddr, exc_info=True)
+ last_exc = e
msg = 'Could not connect to any of %s' % list(map(lambda a: a[4],
addrs))
logger.error(msg)
- raise TTransportException(type=TTransportException.NOT_OPEN, message=msg)
+ raise TTransportException(type=TTransportException.NOT_OPEN, message=msg, inner=last_exc)
def read(self, sz):
try:
diff --git a/lib/py/test/test_socket.py b/lib/py/test/test_socket.py
index 727aceb..af09515 100644
--- a/lib/py/test/test_socket.py
+++ b/lib/py/test/test_socket.py
@@ -30,6 +30,16 @@
class TSocketTest(unittest.TestCase):
+ def test_failed_connection_raises_exception(self):
+ sock = TSocket(host="localhost", port=60606) # unused port
+ with self.assertRaises(TTransportException) as ctx:
+ sock.open()
+ exc = ctx.exception
+ self.assertEqual(exc.type, TTransportException.NOT_OPEN)
+ self.assertIn("Could not connect to any of", exc.message)
+ self.assertIsNotNone(exc.inner)
+ self.assertIn("Connection refused", str(exc.inner))
+
def test_socket_readtimeout_exception(self):
acc = ServerAcceptor(TServerSocket(port=0))
acc.start()