def test_socket_closed(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((client_context.host, client_context.port)) socket_checker = SocketChecker() self.assertFalse(socket_checker.socket_closed(s)) s.close() self.assertTrue(socket_checker.socket_closed(s))
def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 self.sockets = set() self.lock = threading.Lock() self.active_sockets = 0 # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = ( self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker()
def test_socket_closed(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((client_context.host, client_context.port)) socket_checker = SocketChecker() self.assertFalse(socket_checker.socket_closed(s)) s.close() self.assertTrue(socket_checker.socket_closed(s))
def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 # LIFO pool. Sockets are ordered on idle time. Sockets claimed # and returned to pool from the left side. Stale sockets removed # from the right side. self.sockets = collections.deque() self.lock = threading.Lock() self.active_sockets = 0 # Monotonically increasing connection ID required for CMAP Events. self.next_connection_id = 1 self.closed = False # Track whether the sockets in this pool are writeable or not. self.is_writable = None # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake # Don't publish events in Monitor pools. self.enabled_for_cmap = ( self.handshake and self.opts.event_listeners is not None and self.opts.event_listeners.enabled_for_cmap) if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = ( self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker() if self.enabled_for_cmap: self.opts.event_listeners.publish_pool_created( self.address, self.opts.non_default_options)
def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 self.sockets = set() self.lock = threading.Lock() self.active_sockets = 0 # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = ( self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker()
def test_socket_closed_thread_safe(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((client_context.host, client_context.port)) socket_checker = SocketChecker() def check_socket(): for _ in range(1000): self.assertFalse(socket_checker.socket_closed(s)) threads = [] for i in range(3): thread = threading.Thread(target=check_socket) thread.start() threads.append(thread) for thread in threads: thread.join()
class Pool: def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 self.sockets = set() self.lock = threading.Lock() self.active_sockets = 0 # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = ( self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker() def reset(self): with self.lock: self.pool_id += 1 self.pid = os.getpid() sockets, self.sockets = self.sockets, set() self.active_sockets = 0 for sock_info in sockets: sock_info.close() def remove_stale_sockets(self): if self.opts.max_idle_time_ms is not None: with self.lock: for sock_info in self.sockets.copy(): idle_time_ms = 1000 * _time() - sock_info.last_checkin if idle_time_ms > self.opts.max_idle_time_ms: self.sockets.remove(sock_info) sock_info.close() while len( self.sockets) + self.active_sockets < self.opts.min_pool_size: sock_info = self.connect() with self.lock: self.sockets.add(sock_info) def connect(self): """Connect to Mongo and return a new SocketInfo. Can raise ConnectionFailure or CertificateError. Note that the pool does not keep a reference to the socket -- you must call return_socket() when you're done with it. """ sock = None try: sock = _configured_socket(self.address, self.opts) if self.handshake: cmd = SON([ ('ismaster', 1), ('client', self.opts.metadata) ]) ismaster = IsMaster( command(sock, 'admin', cmd, False, False, ReadPreference.PRIMARY, DEFAULT_CODEC_OPTIONS, None, None)) else: ismaster = None return SocketInfo(sock, self, ismaster, self.address) except socket.error as error: if sock is not None: sock.close() _raise_connection_failure(self.address, error) @contextlib.contextmanager def get_socket(self, all_credentials, checkout=False): """Get a socket from the pool. Use with a "with" statement. Returns a :class:`SocketInfo` object wrapping a connected :class:`socket.socket`. This method should always be used in a with-statement:: with pool.get_socket(credentials, checkout) as socket_info: socket_info.send_message(msg) data = socket_info.receive_message(op_code, request_id) The socket is logged in or out as needed to match ``all_credentials`` using the correct authentication mechanism for the server's wire protocol version. Can raise ConnectionFailure or OperationFailure. :Parameters: - `all_credentials`: dict, maps auth source to MongoCredential. - `checkout` (optional): keep socket checked out. """ # First get a socket, then attempt authentication. Simplifies # semaphore management in the face of network errors during auth. sock_info = self._get_socket_no_auth() try: sock_info.check_auth(all_credentials) yield sock_info except: # Exception in caller. Decrement semaphore. self.return_socket(sock_info) raise else: if not checkout: self.return_socket(sock_info) def _get_socket_no_auth(self): """Get or create a SocketInfo. Can raise ConnectionFailure.""" # We use the pid here to avoid issues with fork / multiprocessing. # See test.test_client:TestClient.test_fork for an example of # what could go wrong otherwise if self.pid != os.getpid(): self.reset() # Get a free socket or create one. if not self._socket_semaphore.acquire( True, self.opts.wait_queue_timeout): self._raise_wait_queue_timeout() with self.lock: self.active_sockets += 1 # We've now acquired the semaphore and must release it on error. try: try: # set.pop() isn't atomic in Jython less than 2.7, see # http://bugs.jython.org/issue1854 with self.lock: # Can raise ConnectionFailure. sock_info = self.sockets.pop() except KeyError: # Can raise ConnectionFailure or CertificateError. sock_info = self.connect() else: # Can raise ConnectionFailure. sock_info = self._check(sock_info) except: self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 raise return sock_info def return_socket(self, sock_info): """Return the socket to the pool, or if it's closed discard it.""" if self.pid != os.getpid(): self.reset() else: if sock_info.pool_id != self.pool_id: sock_info.close() elif not sock_info.closed: sock_info.last_checkin = _time() with self.lock: self.sockets.add(sock_info) self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 def _check(self, sock_info): """This side-effecty function checks if this socket has been idle for for longer than the max idle time, or if the socket has been closed by some external network error, and if so, attempts to create a new socket. If this connection attempt fails we raise the ConnectionFailure. Checking sockets lets us avoid seeing *some* :class:`~pymongo.errors.AutoReconnect` exceptions on server hiccups, etc. We only check if the socket was closed by an external error if it has been > 1 second since the socket was checked into the pool, to keep performance reasonable - we can't avoid AutoReconnects completely anyway. """ # How long since socket was last checked in. idle_time_seconds = _time() - sock_info.last_checkin # If socket is idle, open a new one. if (self.opts.max_idle_time_ms is not None and idle_time_seconds * 1000 > self.opts.max_idle_time_ms): sock_info.close() return self.connect() if (self._check_interval_seconds is not None and ( 0 == self._check_interval_seconds or idle_time_seconds > self._check_interval_seconds)): if self.socket_checker.socket_closed(sock_info.sock): sock_info.close() return self.connect() return sock_info def _raise_wait_queue_timeout(self): raise ConnectionFailure( 'Timed out waiting for socket from pool with max_size %r and' ' wait_queue_timeout %r' % ( self.opts.max_pool_size, self.opts.wait_queue_timeout)) def __del__(self): # Avoid ResourceWarnings in Python 3 for sock_info in self.sockets: sock_info.close()
class Pool: def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 # LIFO pool. Sockets are ordered on idle time. Sockets claimed # and returned to pool from the left side. Stale sockets removed # from the right side. self.sockets = collections.deque() self.lock = threading.Lock() self.active_sockets = 0 # Monotonically increasing connection ID required for CMAP Events. self.next_connection_id = 1 self.closed = False # Track whether the sockets in this pool are writeable or not. self.is_writable = None # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake # Don't publish events in Monitor pools. self.enabled_for_cmap = (self.handshake and self.opts.event_listeners is not None and self.opts.event_listeners.enabled_for_cmap) if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = (self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker() if self.enabled_for_cmap: self.opts.event_listeners.publish_pool_created( self.address, self.opts.non_default_options) def _reset(self, close): with self.lock: if self.closed: return self.pool_id += 1 self.pid = os.getpid() sockets, self.sockets = self.sockets, collections.deque() self.active_sockets = 0 if close: self.closed = True listeners = self.opts.event_listeners # CMAP spec says that close() MUST close sockets before publishing the # PoolClosedEvent but that reset() SHOULD close sockets *after* # publishing the PoolClearedEvent. if close: for sock_info in sockets: sock_info.close_socket(ConnectionClosedReason.POOL_CLOSED) if self.enabled_for_cmap: listeners.publish_pool_closed(self.address) else: if self.enabled_for_cmap: listeners.publish_pool_cleared(self.address) for sock_info in sockets: sock_info.close_socket(ConnectionClosedReason.STALE) def update_is_writable(self, is_writable): """Updates the is_writable attribute on all sockets currently in the Pool. """ self.is_writable = is_writable with self.lock: for socket in self.sockets: socket.update_is_writable(self.is_writable) def reset(self): self._reset(close=False) def close(self): self._reset(close=True) def remove_stale_sockets(self): """Removes stale sockets then adds new ones if pool is too small.""" if self.opts.max_idle_time_seconds is not None: with self.lock: while (self.sockets and self.sockets[-1].idle_time_seconds() > self.opts.max_idle_time_seconds): sock_info = self.sockets.pop() sock_info.close_socket(ConnectionClosedReason.IDLE) while True: with self.lock: if (len(self.sockets) + self.active_sockets >= self.opts.min_pool_size): # There are enough sockets in the pool. break # We must acquire the semaphore to respect max_pool_size. if not self._socket_semaphore.acquire(False): break try: sock_info = self.connect() with self.lock: self.sockets.appendleft(sock_info) finally: self._socket_semaphore.release() def connect(self): """Connect to Mongo and return a new SocketInfo. Can raise ConnectionFailure or CertificateError. Note that the pool does not keep a reference to the socket -- you must call return_socket() when you're done with it. """ with self.lock: conn_id = self.next_connection_id self.next_connection_id += 1 listeners = self.opts.event_listeners if self.enabled_for_cmap: listeners.publish_connection_created(self.address, conn_id) sock = None try: sock = _configured_socket(self.address, self.opts) except socket.error as error: if sock is not None: sock.close() if self.enabled_for_cmap: listeners.publish_connection_closed( self.address, conn_id, ConnectionClosedReason.ERROR) _raise_connection_failure(self.address, error) sock_info = SocketInfo(sock, self, self.address, conn_id) if self.handshake: sock_info.ismaster(self.opts.metadata, None) self.is_writable = sock_info.is_writable return sock_info @contextlib.contextmanager def get_socket(self, all_credentials, checkout=False): """Get a socket from the pool. Use with a "with" statement. Returns a :class:`SocketInfo` object wrapping a connected :class:`socket.socket`. This method should always be used in a with-statement:: with pool.get_socket(credentials, checkout) as socket_info: socket_info.send_message(msg) data = socket_info.receive_message(op_code, request_id) The socket is logged in or out as needed to match ``all_credentials`` using the correct authentication mechanism for the server's wire protocol version. Can raise ConnectionFailure or OperationFailure. :Parameters: - `all_credentials`: dict, maps auth source to MongoCredential. - `checkout` (optional): keep socket checked out. """ listeners = self.opts.event_listeners if self.enabled_for_cmap: listeners.publish_connection_check_out_started(self.address) # First get a socket, then attempt authentication. Simplifies # semaphore management in the face of network errors during auth. sock_info = self._get_socket_no_auth() checked_auth = False try: sock_info.check_auth(all_credentials) checked_auth = True if self.enabled_for_cmap: listeners.publish_connection_checked_out( self.address, sock_info.id) yield sock_info except: # Exception in caller. Decrement semaphore. self.return_socket(sock_info, publish_checkin=checked_auth) if self.enabled_for_cmap and not checked_auth: self.opts.event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.CONN_ERROR) raise else: if not checkout: self.return_socket(sock_info) def _get_socket_no_auth(self): """Get or create a SocketInfo. Can raise ConnectionFailure.""" # We use the pid here to avoid issues with fork / multiprocessing. # See test.test_client:TestClient.test_fork for an example of # what could go wrong otherwise if self.pid != os.getpid(): self.reset() if self.closed: if self.enabled_for_cmap: self.opts.event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.POOL_CLOSED) raise _PoolClosedError( 'Attempted to check out a connection from closed connection ' 'pool') # Get a free socket or create one. if not self._socket_semaphore.acquire(True, self.opts.wait_queue_timeout): self._raise_wait_queue_timeout() with self.lock: self.active_sockets += 1 # We've now acquired the semaphore and must release it on error. try: sock_info = None while sock_info is None: try: with self.lock: sock_info = self.sockets.popleft() except IndexError: # Can raise ConnectionFailure or CertificateError. sock_info = self.connect() else: if self._perished(sock_info): sock_info = None except Exception: self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 if self.enabled_for_cmap: self.opts.event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.CONN_ERROR) raise return sock_info def return_socket(self, sock_info, publish_checkin=True): """Return the socket to the pool, or if it's closed discard it. :Parameters: - `sock_info`: The socket to check into the pool. - `publish_checkin`: If False, a ConnectionCheckedInEvent will not be published. """ listeners = self.opts.event_listeners if self.enabled_for_cmap and publish_checkin: listeners.publish_connection_checked_in(self.address, sock_info.id) if self.pid != os.getpid(): self.reset() else: if self.closed: sock_info.close_socket(ConnectionClosedReason.POOL_CLOSED) elif sock_info.pool_id != self.pool_id: sock_info.close_socket(ConnectionClosedReason.STALE) elif not sock_info.closed: sock_info.update_last_checkin_time() sock_info.update_is_writable(self.is_writable) with self.lock: self.sockets.appendleft(sock_info) self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 def _perished(self, sock_info): """This side-effecty function checks if this socket has been idle for for longer than the max idle time, or if the socket has been closed by some external network error. Checking sockets lets us avoid seeing *some* :class:`~pymongo.errors.AutoReconnect` exceptions on server hiccups, etc. We only check if the socket was closed by an external error if it has been > 1 second since the socket was checked into the pool, to keep performance reasonable - we can't avoid AutoReconnects completely anyway. """ idle_time_seconds = sock_info.idle_time_seconds() # If socket is idle, open a new one. if (self.opts.max_idle_time_seconds is not None and idle_time_seconds > self.opts.max_idle_time_seconds): sock_info.close_socket(ConnectionClosedReason.IDLE) return True if (self._check_interval_seconds is not None and (0 == self._check_interval_seconds or idle_time_seconds > self._check_interval_seconds)): if self.socket_checker.socket_closed(sock_info.sock): sock_info.close_socket(ConnectionClosedReason.ERROR) return True return False def _raise_wait_queue_timeout(self): listeners = self.opts.event_listeners if self.enabled_for_cmap: listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.TIMEOUT) raise ConnectionFailure( 'Timed out while checking out a connection from connection pool ' 'with max_size %r and wait_queue_timeout %r' % (self.opts.max_pool_size, self.opts.wait_queue_timeout)) def __del__(self): # Avoid ResourceWarnings in Python 3 # Close all sockets without calling reset() or close() because it is # not safe to acquire a lock in __del__. for sock_info in self.sockets: sock_info.close_socket(None)
class Pool: def __init__(self, address, options, handshake=True): """ :Parameters: - `address`: a (hostname, port) tuple - `options`: a PoolOptions instance - `handshake`: whether to call ismaster for each new SocketInfo """ # Check a socket's health with socket_closed() every once in a while. # Can override for testing: 0 to always check, None to never check. self._check_interval_seconds = 1 self.sockets = set() self.lock = threading.Lock() self.active_sockets = 0 # Keep track of resets, so we notice sockets created before the most # recent reset and close them. self.pool_id = 0 self.pid = os.getpid() self.address = address self.opts = options self.handshake = handshake if (self.opts.wait_queue_multiple is None or self.opts.max_pool_size is None): max_waiters = None else: max_waiters = ( self.opts.max_pool_size * self.opts.wait_queue_multiple) self._socket_semaphore = thread_util.create_semaphore( self.opts.max_pool_size, max_waiters) self.socket_checker = SocketChecker() def reset(self): with self.lock: self.pool_id += 1 self.pid = os.getpid() sockets, self.sockets = self.sockets, set() self.active_sockets = 0 for sock_info in sockets: sock_info.close() def remove_stale_sockets(self): """Removes stale sockets then adds new ones if pool is too small.""" if self.opts.max_idle_time_seconds is not None: with self.lock: for sock_info in self.sockets.copy(): if (sock_info.idle_time_seconds() > self.opts.max_idle_time_seconds): self.sockets.remove(sock_info) sock_info.close() while True: with self.lock: if (len(self.sockets) + self.active_sockets >= self.opts.min_pool_size): # There are enough sockets in the pool. break # We must acquire the semaphore to respect max_pool_size. if not self._socket_semaphore.acquire(False): break try: sock_info = self.connect() with self.lock: self.sockets.add(sock_info) finally: self._socket_semaphore.release() def connect(self): """Connect to Mongo and return a new SocketInfo. Can raise ConnectionFailure or CertificateError. Note that the pool does not keep a reference to the socket -- you must call return_socket() when you're done with it. """ sock = None try: sock = _configured_socket(self.address, self.opts) except socket.error as error: if sock is not None: sock.close() _raise_connection_failure(self.address, error) sock_info = SocketInfo(sock, self, self.address) if self.handshake: sock_info.ismaster(self.opts.metadata, None) return sock_info @contextlib.contextmanager def get_socket(self, all_credentials, checkout=False): """Get a socket from the pool. Use with a "with" statement. Returns a :class:`SocketInfo` object wrapping a connected :class:`socket.socket`. This method should always be used in a with-statement:: with pool.get_socket(credentials, checkout) as socket_info: socket_info.send_message(msg) data = socket_info.receive_message(op_code, request_id) The socket is logged in or out as needed to match ``all_credentials`` using the correct authentication mechanism for the server's wire protocol version. Can raise ConnectionFailure or OperationFailure. :Parameters: - `all_credentials`: dict, maps auth source to MongoCredential. - `checkout` (optional): keep socket checked out. """ # First get a socket, then attempt authentication. Simplifies # semaphore management in the face of network errors during auth. sock_info = self._get_socket_no_auth() try: sock_info.check_auth(all_credentials) yield sock_info except: # Exception in caller. Decrement semaphore. self.return_socket(sock_info) raise else: if not checkout: self.return_socket(sock_info) def _get_socket_no_auth(self): """Get or create a SocketInfo. Can raise ConnectionFailure.""" # We use the pid here to avoid issues with fork / multiprocessing. # See test.test_client:TestClient.test_fork for an example of # what could go wrong otherwise if self.pid != os.getpid(): self.reset() # Get a free socket or create one. if not self._socket_semaphore.acquire( True, self.opts.wait_queue_timeout): self._raise_wait_queue_timeout() with self.lock: self.active_sockets += 1 # We've now acquired the semaphore and must release it on error. try: try: # set.pop() isn't atomic in Jython less than 2.7, see # http://bugs.jython.org/issue1854 with self.lock: # Can raise ConnectionFailure. sock_info = self.sockets.pop() except KeyError: # Can raise ConnectionFailure or CertificateError. sock_info = self.connect() else: # Can raise ConnectionFailure. sock_info = self._check(sock_info) except: self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 raise return sock_info def return_socket(self, sock_info): """Return the socket to the pool, or if it's closed discard it.""" if self.pid != os.getpid(): self.reset() else: if sock_info.pool_id != self.pool_id: sock_info.close() elif not sock_info.closed: sock_info.update_last_checkin_time() with self.lock: self.sockets.add(sock_info) self._socket_semaphore.release() with self.lock: self.active_sockets -= 1 def _check(self, sock_info): """This side-effecty function checks if this socket has been idle for for longer than the max idle time, or if the socket has been closed by some external network error, and if so, attempts to create a new socket. If this connection attempt fails we raise the ConnectionFailure. Checking sockets lets us avoid seeing *some* :class:`~pymongo.errors.AutoReconnect` exceptions on server hiccups, etc. We only check if the socket was closed by an external error if it has been > 1 second since the socket was checked into the pool, to keep performance reasonable - we can't avoid AutoReconnects completely anyway. """ idle_time_seconds = sock_info.idle_time_seconds() # If socket is idle, open a new one. if (self.opts.max_idle_time_seconds is not None and idle_time_seconds > self.opts.max_idle_time_seconds): sock_info.close() return self.connect() if (self._check_interval_seconds is not None and ( 0 == self._check_interval_seconds or idle_time_seconds > self._check_interval_seconds)): if self.socket_checker.socket_closed(sock_info.sock): sock_info.close() return self.connect() return sock_info def _raise_wait_queue_timeout(self): raise ConnectionFailure( 'Timed out waiting for socket from pool with max_size %r and' ' wait_queue_timeout %r' % ( self.opts.max_pool_size, self.opts.wait_queue_timeout)) def __del__(self): # Avoid ResourceWarnings in Python 3 for sock_info in self.sockets: sock_info.close()