Skip to content

Commit d98a745

Browse files
committed
PYTHON-1067 - Implement SDAM Monitoring
1 parent 1060814 commit d98a745

24 files changed

+1812
-47
lines changed

doc/api/pymongo/monitoring.rst

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,33 @@
77
.. autofunction:: register(listener)
88
.. autoclass:: CommandListener
99
:members:
10+
.. autoclass:: ServerListener
11+
:members:
12+
.. autoclass:: ServerHeartbeatListener
13+
:members:
14+
.. autoclass:: TopologyListener
15+
:members:
1016
.. autoclass:: CommandStartedEvent
1117
:members:
12-
:inherited-members:
1318
.. autoclass:: CommandSucceededEvent
1419
:members:
15-
:inherited-members:
1620
.. autoclass:: CommandFailedEvent
1721
:members:
18-
:inherited-members:
22+
.. autoclass:: ServerDescriptionChangedEvent
23+
:members:
24+
.. autoclass:: ServerOpeningEvent
25+
:members:
26+
.. autoclass:: ServerClosedEvent
27+
:members:
28+
.. autoclass:: TopologyDescriptionChangedEvent
29+
:members:
30+
.. autoclass:: TopologyOpenedEvent
31+
:members:
32+
.. autoclass:: TopologyClosedEvent
33+
:members:
34+
.. autoclass:: ServerHeartbeatStartedEvent
35+
:members:
36+
.. autoclass:: ServerHeartbeatSucceededEvent
37+
:members:
38+
.. autoclass:: ServerHeartbeatFailedEvent
39+
:members:

pymongo/common.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
# Frequency to process kill-cursors, in seconds. See MongoClient.close_cursor.
5050
KILL_CURSOR_FREQUENCY = 1
5151

52+
# Frequency to process events queue, in seconds.
53+
EVENTS_QUEUE_FREQUENCY = 1
54+
5255
# How long to wait, in seconds, for a suitable server to be found before
5356
# aborting an operation. For example, if the client attempts an insert
5457
# during a replica set election, SERVER_SELECTION_TIMEOUT governs the

pymongo/monitor.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def __init__(
4444
self._pool = pool
4545
self._settings = topology_settings
4646
self._avg_round_trip_time = MovingAverage()
47+
self._listeners = self._settings._pool_options.event_listeners
48+
pub = self._listeners is not None
49+
self._publish = pub and self._listeners.enabled_for_server_heartbeat
4750

4851
# We strongly reference the executor and it weakly references us via
4952
# this closure. When the monitor is freed, stop the executor soon.
@@ -61,7 +64,7 @@ def target():
6164
name="pymongo_server_monitor_thread")
6265

6366
self._executor = executor
64-
67+
6568
# Avoid cycles. When self or topology is freed, stop executor soon.
6669
self_ref = weakref.ref(self, executor.close)
6770
self._topology = weakref.proxy(topology, executor.close)
@@ -110,24 +113,34 @@ def _check_with_retry(self):
110113
address = self._server_description.address
111114
retry = self._server_description.server_type != SERVER_TYPE.Unknown
112115

116+
start = _time()
113117
try:
114118
return self._check_once()
115119
except ReferenceError:
116120
raise
117121
except Exception as error:
122+
error_time = _time() - start
118123
self._topology.reset_pool(address)
119124
default = ServerDescription(address, error=error)
120125
if not retry:
126+
if self._publish:
127+
self._listeners.publish_server_heartbeat_failed(
128+
address, error_time, error)
121129
self._avg_round_trip_time.reset()
122130
# Server type defaults to Unknown.
123131
return default
124132

125133
# Try a second and final time. If it fails return original error.
134+
start = _time()
126135
try:
127136
return self._check_once()
128137
except ReferenceError:
129138
raise
130-
except Exception:
139+
except Exception as error:
140+
error_time = _time() - start
141+
if self._publish:
142+
self._listeners.publish_server_heartbeat_failed(
143+
address, error_time, error)
131144
self._avg_round_trip_time.reset()
132145
return default
133146

@@ -136,13 +149,19 @@ def _check_once(self):
136149
137150
Returns a ServerDescription, or raises an exception.
138151
"""
152+
address = self._server_description.address
153+
if self._publish:
154+
self._listeners.publish_server_heartbeat_started(address)
139155
with self._pool.get_socket({}) as sock_info:
140156
response, round_trip_time = self._check_with_socket(sock_info)
141157
self._avg_round_trip_time.add_sample(round_trip_time)
142158
sd = ServerDescription(
143-
address=self._server_description.address,
159+
address=address,
144160
ismaster=response,
145161
round_trip_time=self._avg_round_trip_time.get())
162+
if self._publish:
163+
self._listeners.publish_server_heartbeat_succeeded(
164+
address, round_trip_time, response)
146165

147166
return sd
148167

0 commit comments

Comments
 (0)