Merge pull request #385 from datastax/381

PYTHON-381 - Use connect_timeout for socket connect in addition to negotiation
This commit is contained in:
Michael Penick
2015-08-19 08:41:50 -07:00
3 changed files with 20 additions and 7 deletions

View File

@@ -242,7 +242,7 @@ class Connection(object):
def __init__(self, host='127.0.0.1', port=9042, authenticator=None, def __init__(self, host='127.0.0.1', port=9042, authenticator=None,
ssl_options=None, sockopts=None, compression=True, ssl_options=None, sockopts=None, compression=True,
cql_version=None, protocol_version=MAX_SUPPORTED_VERSION, is_control_connection=False, cql_version=None, protocol_version=MAX_SUPPORTED_VERSION, is_control_connection=False,
user_type_map=None): user_type_map=None, connect_timeout=None):
self.host = host self.host = host
self.port = port self.port = port
self.authenticator = authenticator self.authenticator = authenticator
@@ -253,6 +253,7 @@ class Connection(object):
self.protocol_version = protocol_version self.protocol_version = protocol_version
self.is_control_connection = is_control_connection self.is_control_connection = is_control_connection
self.user_type_map = user_type_map self.user_type_map = user_type_map
self.connect_timeout = connect_timeout
self._push_watchers = defaultdict(set) self._push_watchers = defaultdict(set)
self._requests = {} self._requests = {}
self._iobuf = io.BytesIO() self._iobuf = io.BytesIO()
@@ -298,8 +299,11 @@ class Connection(object):
succeeded in connecting and are ready for service (or succeeded in connecting and are ready for service (or
raises an exception otherwise). raises an exception otherwise).
""" """
start = time.time()
kwargs['connect_timeout'] = timeout
conn = cls(host, *args, **kwargs) conn = cls(host, *args, **kwargs)
conn.connected_event.wait(timeout) elapsed = time.time() - start
conn.connected_event.wait(timeout - elapsed)
if conn.last_error: if conn.last_error:
if conn.is_unsupported_proto_version: if conn.is_unsupported_proto_version:
raise ProtocolVersionUnsupported(host, conn.protocol_version) raise ProtocolVersionUnsupported(host, conn.protocol_version)
@@ -320,7 +324,7 @@ class Connection(object):
if not self._ssl_impl: if not self._ssl_impl:
raise Exception("This version of Python was not compiled with SSL support") raise Exception("This version of Python was not compiled with SSL support")
self._socket = self._ssl_impl.wrap_socket(self._socket, **self.ssl_options) self._socket = self._ssl_impl.wrap_socket(self._socket, **self.ssl_options)
self._socket.settimeout(1.0) self._socket.settimeout(self.connect_timeout)
self._socket.connect(sockaddr) self._socket.connect(sockaddr)
sockerr = None sockerr = None
break break
@@ -331,7 +335,7 @@ class Connection(object):
sockerr = err sockerr = err
if sockerr: if sockerr:
raise socket.error(sockerr.errno, "Tried connecting to %s. Last error: %s" % ([a[4] for a in addresses], sockerr.strerror)) raise socket.error(sockerr.errno, "Tried connecting to %s. Last error: %s" % ([a[4] for a in addresses], sockerr.strerror or sockerr))
if self.sockopts: if self.sockopts:
for args in self.sockopts: for args in self.sockopts:

View File

@@ -200,7 +200,8 @@ class TwistedConnection(Connection):
""" """
self.connector = reactor.connectTCP( self.connector = reactor.connectTCP(
host=self.host, port=self.port, host=self.host, port=self.port,
factory=TwistedConnectionClientFactory(self)) factory=TwistedConnectionClientFactory(self),
timeout=self.connect_timeout)
def client_connection_made(self): def client_connection_made(self):
""" """

View File

@@ -19,7 +19,9 @@ except ImportError:
from functools import partial from functools import partial
from six.moves import range from six.moves import range
import sys
from threading import Thread, Event from threading import Thread, Event
import time
from cassandra import ConsistencyLevel, OperationTimedOut from cassandra import ConsistencyLevel, OperationTimedOut
from cassandra.cluster import NoHostAvailable from cassandra.cluster import NoHostAvailable
@@ -46,7 +48,7 @@ class ConnectionTests(object):
def setUp(self): def setUp(self):
self.klass.initialize_reactor() self.klass.initialize_reactor()
def get_connection(self): def get_connection(self, timeout=5):
""" """
Helper method to solve automated testing issues within Jenkins. Helper method to solve automated testing issues within Jenkins.
Officially patched under the 2.0 branch through Officially patched under the 2.0 branch through
@@ -58,7 +60,7 @@ class ConnectionTests(object):
e = None e = None
for i in range(5): for i in range(5):
try: try:
conn = self.klass.factory(host='127.0.0.1', timeout=5, protocol_version=PROTOCOL_VERSION) conn = self.klass.factory(host='127.0.0.1', timeout=timeout, protocol_version=PROTOCOL_VERSION)
break break
except (OperationTimedOut, NoHostAvailable) as e: except (OperationTimedOut, NoHostAvailable) as e:
continue continue
@@ -224,6 +226,12 @@ class ConnectionTests(object):
for t in threads: for t in threads:
t.join() t.join()
def test_connect_timeout(self):
start = time.time()
self.assertRaises(Exception, self.get_connection, timeout=sys.float_info.min)
end = time.time()
self.assertAlmostEqual(start, end, 1)
class AsyncoreConnectionTests(ConnectionTests, unittest.TestCase): class AsyncoreConnectionTests(ConnectionTests, unittest.TestCase):