1414
1515"""Class to monitor a MongoDB server on a background thread."""
1616
17+ from __future__ import annotations
18+
1719import atexit
1820import time
1921import weakref
20- from typing import Any , Mapping , cast
22+ from typing import TYPE_CHECKING , Any , List , Mapping , Optional , Tuple , cast
2123
2224from pymongo import common , periodic_executor
2325from pymongo ._csot import MovingMinimum
2931from pymongo .server_description import ServerDescription
3032from pymongo .srv_resolver import _SrvResolver
3133
34+ if TYPE_CHECKING :
35+ from pymongo .pool import Connection , Pool
36+ from pymongo .settings import TopologySettings
37+ from pymongo .topology import Topology
38+
3239
33- def _sanitize (error ) :
40+ def _sanitize (error : Exception ) -> None :
3441 """PYTHON-2433 Clear error traceback info."""
3542 error .__traceback__ = None
3643 error .__context__ = None
3744 error .__cause__ = None
3845
3946
4047class MonitorBase :
41- def __init__ (self , topology , name , interval , min_interval ):
48+ def __init__ (self , topology : Topology , name : str , interval : int , min_interval : float ):
4249 """Base class to do periodic work on a background thread.
4350
4451 The background thread is signaled to stop when the Topology or
4552 this instance is freed.
4653 """
4754 # We strongly reference the executor and it weakly references us via
4855 # this closure. When the monitor is freed, stop the executor soon.
49- def target ():
56+ def target () -> bool :
5057 monitor = self_ref ()
5158 if monitor is None :
5259 return False # Stop the executor.
@@ -59,7 +66,7 @@ def target():
5966
6067 self ._executor = executor
6168
62- def _on_topology_gc (dummy = None ):
69+ def _on_topology_gc (dummy : Optional [ Topology ] = None ) -> None :
6370 # This prevents GC from waiting 10 seconds for hello to complete
6471 # See test_cleanup_executors_on_client_del.
6572 monitor = self_ref ()
@@ -71,35 +78,41 @@ def _on_topology_gc(dummy=None):
7178 self ._topology = weakref .proxy (topology , _on_topology_gc )
7279 _register (self )
7380
74- def open (self ):
81+ def open (self ) -> None :
7582 """Start monitoring, or restart after a fork.
7683
7784 Multiple calls have no effect.
7885 """
7986 self ._executor .open ()
8087
81- def gc_safe_close (self ):
88+ def gc_safe_close (self ) -> None :
8289 """GC safe close."""
8390 self ._executor .close ()
8491
85- def close (self ):
92+ def close (self ) -> None :
8693 """Close and stop monitoring.
8794
8895 open() restarts the monitor after closing.
8996 """
9097 self .gc_safe_close ()
9198
92- def join (self , timeout = None ):
99+ def join (self , timeout : Optional [ int ] = None ) -> None :
93100 """Wait for the monitor to stop."""
94101 self ._executor .join (timeout )
95102
96- def request_check (self ):
103+ def request_check (self ) -> None :
97104 """If the monitor is sleeping, wake it soon."""
98105 self ._executor .wake ()
99106
100107
101108class Monitor (MonitorBase ):
102- def __init__ (self , server_description , topology , pool , topology_settings ):
109+ def __init__ (
110+ self ,
111+ server_description : ServerDescription ,
112+ topology : Topology ,
113+ pool : Pool ,
114+ topology_settings : TopologySettings ,
115+ ):
103116 """Class to monitor a MongoDB server on a background thread.
104117
105118 Pass an initial ServerDescription, a Topology, a Pool, and
@@ -128,7 +141,7 @@ def __init__(self, server_description, topology, pool, topology_settings):
128141 )
129142 self .heartbeater = None
130143
131- def cancel_check (self ):
144+ def cancel_check (self ) -> None :
132145 """Cancel any concurrent hello check.
133146
134147 Note: this is called from a weakref.proxy callback and MUST NOT take
@@ -141,7 +154,7 @@ def cancel_check(self):
141154 # (depending on the platform).
142155 context .cancel ()
143156
144- def _start_rtt_monitor (self ):
157+ def _start_rtt_monitor (self ) -> None :
145158 """Start an _RttMonitor that periodically runs ping."""
146159 # If this monitor is closed directly before (or during) this open()
147160 # call, the _RttMonitor will not be closed. Checking if this monitor
@@ -150,23 +163,23 @@ def _start_rtt_monitor(self):
150163 if self ._executor ._stopped :
151164 self ._rtt_monitor .close ()
152165
153- def gc_safe_close (self ):
166+ def gc_safe_close (self ) -> None :
154167 self ._executor .close ()
155168 self ._rtt_monitor .gc_safe_close ()
156169 self .cancel_check ()
157170
158- def close (self ):
171+ def close (self ) -> None :
159172 self .gc_safe_close ()
160173 self ._rtt_monitor .close ()
161174 # Increment the generation and maybe close the socket. If the executor
162175 # thread has the socket checked out, it will be closed when checked in.
163176 self ._reset_connection ()
164177
165- def _reset_connection (self ):
178+ def _reset_connection (self ) -> None :
166179 # Clear our pooled connection.
167180 self ._pool .reset ()
168181
169- def _run (self ):
182+ def _run (self ) -> None :
170183 try :
171184 prev_sd = self ._server_description
172185 try :
@@ -203,7 +216,7 @@ def _run(self):
203216 # Topology was garbage-collected.
204217 self .close ()
205218
206- def _check_server (self ):
219+ def _check_server (self ) -> ServerDescription :
207220 """Call hello or read the next streaming response.
208221
209222 Returns a ServerDescription.
@@ -234,7 +247,7 @@ def _check_server(self):
234247 # Server type defaults to Unknown.
235248 return ServerDescription (address , error = error )
236249
237- def _check_once (self ):
250+ def _check_once (self ) -> ServerDescription :
238251 """A single attempt to call hello.
239252
240253 Returns a ServerDescription, or raises an exception.
@@ -259,7 +272,7 @@ def _check_once(self):
259272 )
260273 return sd
261274
262- def _check_with_socket (self , conn ) :
275+ def _check_with_socket (self , conn : Connection ) -> Tuple [ Hello , float ] :
263276 """Return (Hello, round_trip_time).
264277
265278 Can raise ConnectionFailure or OperationFailure.
@@ -283,7 +296,7 @@ def _check_with_socket(self, conn):
283296
284297
285298class SrvMonitor (MonitorBase ):
286- def __init__ (self , topology , topology_settings ):
299+ def __init__ (self , topology : Topology , topology_settings : TopologySettings ):
287300 """Class to poll SRV records on a background thread.
288301
289302 Pass a Topology and a TopologySettings.
@@ -298,9 +311,10 @@ def __init__(self, topology, topology_settings):
298311 )
299312 self ._settings = topology_settings
300313 self ._seedlist = self ._settings ._seeds
301- self ._fqdn = self ._settings .fqdn
314+ assert isinstance (self ._settings .fqdn , str )
315+ self ._fqdn : str = self ._settings .fqdn
302316
303- def _run (self ):
317+ def _run (self ) -> None :
304318 seedlist = self ._get_seedlist ()
305319 if seedlist :
306320 self ._seedlist = seedlist
@@ -310,7 +324,7 @@ def _run(self):
310324 # Topology was garbage-collected.
311325 self .close ()
312326
313- def _get_seedlist (self ):
327+ def _get_seedlist (self ) -> Optional [ List [ Tuple [ str , Any ]]] :
314328 """Poll SRV records for a seedlist.
315329
316330 Returns a list of ServerDescriptions.
@@ -338,7 +352,7 @@ def _get_seedlist(self):
338352
339353
340354class _RttMonitor (MonitorBase ):
341- def __init__ (self , topology , topology_settings , pool ):
355+ def __init__ (self , topology : Topology , topology_settings : TopologySettings , pool : Pool ):
342356 """Maintain round trip times for a server.
343357
344358 The Topology is weakly referenced.
@@ -355,30 +369,30 @@ def __init__(self, topology, topology_settings, pool):
355369 self ._moving_min = MovingMinimum ()
356370 self ._lock = _create_lock ()
357371
358- def close (self ):
372+ def close (self ) -> None :
359373 self .gc_safe_close ()
360374 # Increment the generation and maybe close the socket. If the executor
361375 # thread has the socket checked out, it will be closed when checked in.
362376 self ._pool .reset ()
363377
364- def add_sample (self , sample ) :
378+ def add_sample (self , sample : float ) -> None :
365379 """Add a RTT sample."""
366380 with self ._lock :
367381 self ._moving_average .add_sample (sample )
368382 self ._moving_min .add_sample (sample )
369383
370- def get (self ):
384+ def get (self ) -> Tuple [ Optional [ float ], float ] :
371385 """Get the calculated average, or None if no samples yet and the min."""
372386 with self ._lock :
373387 return self ._moving_average .get (), self ._moving_min .get ()
374388
375- def reset (self ):
389+ def reset (self ) -> None :
376390 """Reset the average RTT."""
377391 with self ._lock :
378392 self ._moving_average .reset ()
379393 self ._moving_min .reset ()
380394
381- def _run (self ):
395+ def _run (self ) -> None :
382396 try :
383397 # NOTE: This thread is only run when using the streaming
384398 # heartbeat protocol (MongoDB 4.4+).
@@ -391,7 +405,7 @@ def _run(self):
391405 except Exception :
392406 self ._pool .reset ()
393407
394- def _ping (self ):
408+ def _ping (self ) -> float :
395409 """Run a "hello" command and return the RTT."""
396410 with self ._pool .checkout () as conn :
397411 if self ._executor ._stopped :
@@ -407,16 +421,16 @@ def _ping(self):
407421_MONITORS = set ()
408422
409423
410- def _register (monitor ) :
424+ def _register (monitor : MonitorBase ) -> None :
411425 ref = weakref .ref (monitor , _unregister )
412426 _MONITORS .add (ref )
413427
414428
415- def _unregister (monitor_ref ) :
429+ def _unregister (monitor_ref : weakref . ReferenceType [ MonitorBase ]) -> None :
416430 _MONITORS .remove (monitor_ref )
417431
418432
419- def _shutdown_monitors ():
433+ def _shutdown_monitors () -> None :
420434 if _MONITORS is None :
421435 return
422436
@@ -432,7 +446,7 @@ def _shutdown_monitors():
432446 monitor = None
433447
434448
435- def _shutdown_resources ():
449+ def _shutdown_resources () -> None :
436450 # _shutdown_monitors/_shutdown_executors may already be GC'd at shutdown.
437451 shutdown = _shutdown_monitors
438452 if shutdown : # type:ignore[truthy-function]
0 commit comments