PYTHON-525 Socket timeout for monitoring is connect_timeout.
The spec's justification is that while a client waits for a server to respond to a connection, the client does not know if the server will respond eventually or if it is down. Users help the client guess by supplying a reasonable connectTimeoutMS for their network. The socketTimeoutMS, on the other hand, must account for both network latency and the operation's duration. Applications should set a long or infinite socketTimeoutMS to wait for long-running operations. A socket used for monitoring does two things: it connects and calls ismaster. Both operations are fast on the server, so only network latency matters. Thus both operations use connectTimeoutMS, since that is the value users supply to help the client guess if a server is down, based on users' knowledge of expected latencies on their networks.
This commit is contained in:
parent
148bbc2fb2
commit
081ca08163
@ -20,6 +20,7 @@ import time
|
||||
|
||||
from bson.py3compat import itervalues
|
||||
from pymongo import common
|
||||
from pymongo.pool import PoolOptions
|
||||
from pymongo.topology_description import (updated_topology_description,
|
||||
TOPOLOGY_TYPE,
|
||||
TopologyDescription)
|
||||
@ -248,12 +249,19 @@ class Topology(object):
|
||||
"""
|
||||
for address, sd in self._description.server_descriptions().items():
|
||||
if address not in self._servers:
|
||||
m = self._settings.monitor_class(
|
||||
sd, self, self._create_pool(address), self._settings)
|
||||
monitor = self._settings.monitor_class(
|
||||
server_description=sd,
|
||||
topology=self,
|
||||
pool=self._create_pool_for_monitor(address),
|
||||
topology_settings=self._settings)
|
||||
|
||||
s = Server(sd, self._create_pool(address), m)
|
||||
self._servers[address] = s
|
||||
s.open()
|
||||
server = Server(
|
||||
server_description=sd,
|
||||
pool=self._create_pool_for_server(address),
|
||||
monitor=monitor)
|
||||
|
||||
self._servers[address] = server
|
||||
server.open()
|
||||
else:
|
||||
self._servers[address].description = sd
|
||||
|
||||
@ -262,5 +270,18 @@ class Topology(object):
|
||||
server.close()
|
||||
self._servers.pop(address)
|
||||
|
||||
def _create_pool(self, address):
|
||||
def _create_pool_for_server(self, address):
|
||||
return self._settings.pool_class(address, self._settings.pool_options)
|
||||
|
||||
def _create_pool_for_monitor(self, address):
|
||||
options = self._settings.pool_options
|
||||
|
||||
# According to the Server Discovery And Monitoring Spec, monitors use
|
||||
# connect_timeout for both connect_timeout and socket_timeout. The
|
||||
# pool only has one socket so max_pool_size and so on aren't needed.
|
||||
return self._settings.pool_class(
|
||||
address,
|
||||
PoolOptions(connect_timeout=options.connect_timeout,
|
||||
socket_timeout=options.connect_timeout,
|
||||
ssl_context=options.ssl_context,
|
||||
socket_keepalive=True))
|
||||
|
||||
@ -30,6 +30,7 @@ from pymongo.errors import (ConfigurationError,
|
||||
ConnectionFailure)
|
||||
from pymongo.ismaster import IsMaster
|
||||
from pymongo.monitor import Monitor
|
||||
from pymongo.pool import PoolOptions
|
||||
from pymongo.read_preferences import MovingAverage
|
||||
from pymongo.server_description import ServerDescription
|
||||
from pymongo.server_selectors import (any_server_selector,
|
||||
@ -133,6 +134,24 @@ class TopologyTest(unittest.TestCase):
|
||||
super(TopologyTest, self).tearDown()
|
||||
|
||||
|
||||
class TestTopologyConfiguration(TopologyTest):
|
||||
def test_timeout_configuration(self):
|
||||
pool_options = PoolOptions(connect_timeout=1, socket_timeout=2)
|
||||
topology_settings = TopologySettings(pool_options=pool_options)
|
||||
t = Topology(topology_settings=topology_settings)
|
||||
server = t.select_server(any_server_selector)
|
||||
|
||||
# The pool for application operations obeys our settings.
|
||||
self.assertEqual(1, server._pool.opts.connect_timeout)
|
||||
self.assertEqual(2, server._pool.opts.socket_timeout)
|
||||
|
||||
# The pool for monitoring operations uses our connect_timeout as both
|
||||
# its connect_timeout and its socket_timeout.
|
||||
monitor = server._monitor
|
||||
self.assertEqual(1, monitor._pool.opts.connect_timeout)
|
||||
self.assertEqual(1, monitor._pool.opts.socket_timeout)
|
||||
|
||||
|
||||
class TestSingleServerTopology(TopologyTest):
|
||||
def test_direct_connection(self):
|
||||
for server_type, ismaster_response in [
|
||||
|
||||
Loading…
Reference in New Issue
Block a user