Skip to content

Commit d7289d0

Browse files
author
Mike Dirolf
committed
add 'network_timeout' option to Connection instances to specify timeout for socket operations
1 parent 6913a0f commit d7289d0

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

pymongo/connection.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class Connection(object): # TODO support auth for pooling
5050

5151
def __init__(self, host=None, port=None, pool_size=None,
5252
auto_start_request=None, timeout=None, slave_okay=False,
53-
_connect=True):
53+
network_timeout=None, _connect=True):
5454
"""Open a new connection to a Mongo instance at host:port.
5555
5656
The resultant connection object has connection-pooling built in. It
@@ -82,6 +82,8 @@ def __init__(self, host=None, port=None, pool_size=None,
8282
- `timeout` (optional): max time to wait when attempting to acquire a
8383
connection from the connection pool before raising an exception -
8484
can be set to -1 to wait indefinitely
85+
- `network_timeout` (optional): timeout (in seconds) to use for socket
86+
operations - default is no timeout
8587
"""
8688
if host is None:
8789
host = self.HOST
@@ -128,6 +130,8 @@ def __init__(self, host=None, port=None, pool_size=None,
128130
self.__sockets = [None for _ in range(self.__pool_size)]
129131
self.__currently_resetting = False
130132

133+
self.__network_timeout = network_timeout
134+
131135
# cache of existing indexes used by ensure_index ops
132136
self.__index_cache = {}
133137

@@ -296,7 +300,7 @@ def __find_master(self):
296300
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
297301
sock.settimeout(_CONNECT_TIMEOUT)
298302
sock.connect((host, port))
299-
sock.settimeout(None)
303+
sock.settimeout(self.__network_timeout)
300304
master = self.__master(sock)
301305
if master is True:
302306
self.__host = host
@@ -350,7 +354,7 @@ def __connect(self, socket_number):
350354
sock = self.__sockets[socket_number]
351355
sock.settimeout(_CONNECT_TIMEOUT)
352356
sock.connect((self.host(), self.port()))
353-
sock.settimeout(None)
357+
sock.settimeout(self.__network_timeout)
354358
_logger.debug("connected")
355359
return
356360
except socket.error:
@@ -493,8 +497,8 @@ def receive(length):
493497
while len(message) < length:
494498
try:
495499
chunk = sock.recv(length - len(message))
496-
except socket.error:
497-
raise ConnectionFailure("connection closed")
500+
except socket.error, e:
501+
raise ConnectionFailure(e)
498502
if chunk == "":
499503
raise ConnectionFailure("connection closed")
500504
message += chunk

test/test_connection.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,30 @@ def iterate():
128128

129129
self.assertRaises(TypeError, iterate)
130130

131+
def test_socket_timeout(self):
132+
no_timeout = Connection(self.host, self.port)
133+
timeout = Connection(self.host, self.port, network_timeout=0.25)
134+
135+
no_timeout.pymongo_test.drop_collection("test")
136+
137+
no_timeout.pymongo_test.test.save({"x": 1})
138+
139+
where_func = """function (doc) {
140+
var d = new Date().getTime() + 500;
141+
var x = new Date().getTime();
142+
while (x < d) {
143+
x = new Date().getTime();
144+
}
145+
return true;
146+
}"""
147+
148+
def get_x(db):
149+
return db.test.find().where(where_func).next()["x"]
150+
151+
self.assertEqual(1, get_x(no_timeout.pymongo_test))
152+
self.assertRaises(ConnectionFailure, get_x, timeout.pymongo_test)
153+
self.assertEqual(1, no_timeout.pymongo_test.test.find().next()["x"])
154+
155+
131156
if __name__ == "__main__":
132157
unittest.main()

0 commit comments

Comments
 (0)