Skip to content

Commit 7e84167

Browse files
author
Mike Dirolf
committed
best effort to handle auto-reconnection transparently PYTHON-108
1 parent 7d7c0c5 commit 7e84167

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

pymongo/connection.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@
3535

3636
import datetime
3737
import os
38+
import select
3839
import socket
3940
import struct
4041
import threading
42+
import time
4143
import warnings
4244

4345
from pymongo import (database,
@@ -113,6 +115,16 @@ def _parse_uri(uri, default_port):
113115
return (host_list, database, username, password)
114116

115117

118+
def _closed(sock):
119+
"""Return True if we know socket has been closed, False otherwise.
120+
"""
121+
rd, _, _ = select.select([sock], [], [], 0)
122+
try:
123+
return len(rd) and sock.recv() == ""
124+
except:
125+
return True
126+
127+
116128
class _Pool(threading.local):
117129
"""A simple connection pool.
118130
@@ -280,6 +292,7 @@ def __init__(self, host=None, port=None, pool_size=None,
280292
self.__cursor_manager = CursorManager(self)
281293

282294
self.__pool = _Pool(self.__connect)
295+
self.__last_checkout = time.time()
283296

284297
self.__network_timeout = network_timeout
285298
self.__document_class = document_class
@@ -515,6 +528,26 @@ def __connect(self):
515528
self.disconnect()
516529
raise AutoReconnect("could not connect to %r" % list(self.__nodes))
517530

531+
def __socket(self):
532+
"""Get a socket from the pool.
533+
534+
If it's been > 1 second since the last time we checked out a
535+
socket, we also check to see if the socket has been closed -
536+
this let's us avoid seeing *some*
537+
:class:`~pymongo.errors.AutoReconnect` exceptions on server
538+
hiccups, etc. We only do this if it's been > 1 second since
539+
the last socket checkout, to keep performance reasonable - we
540+
can't avoid those completely anyway.
541+
"""
542+
sock = self.__pool.socket()
543+
t = time.time()
544+
if t - self.__last_checkout > 1:
545+
if _closed(sock):
546+
self.disconnect()
547+
sock = self.__pool.socket()
548+
self.__last_checkout = t
549+
return sock
550+
518551
def disconnect(self):
519552
"""Disconnect from MongoDB.
520553
@@ -595,7 +628,7 @@ def _send_message(self, message, with_last_error=False):
595628
- `with_last_error`: check getLastError status after sending the
596629
message
597630
"""
598-
sock = self.__pool.socket()
631+
sock = self.__socket()
599632
try:
600633
(request_id, data) = message
601634
sock.sendall(data)
@@ -658,7 +691,7 @@ def _send_message_with_response(self, message,
658691
:Parameters:
659692
- `message`: (request_id, data) pair making up the message to send
660693
"""
661-
sock = self.__pool.socket()
694+
sock = self.__socket()
662695

663696
try:
664697
try:

0 commit comments

Comments
 (0)