From 1ab83f72cfdf6d088234eec4614d515e3616d079 Mon Sep 17 00:00:00 2001 From: "A. Jesse Jiryu Davis" Date: Thu, 18 Dec 2014 09:35:15 -0500 Subject: [PATCH] PYTHON-799 Break ref cycle in Monitor. Previous code to avoid the cycle was wrong. --- pymongo/monitor.py | 13 +++++++++---- pymongo/periodic_executor.py | 11 ++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/pymongo/monitor.py b/pymongo/monitor.py index 89faaca03..6e4eb812a 100644 --- a/pymongo/monitor.py +++ b/pymongo/monitor.py @@ -41,7 +41,7 @@ class Monitor(object): """ self._server_description = server_description - # A weakref callback, takes ref to the dead topology as its parameter. + # A weakref callback, takes ref to the freed topology as its parameter. def close(dummy): self.close() @@ -51,10 +51,15 @@ class Monitor(object): self._avg_round_trip_time = MovingAverage() # We strongly reference the executor and it weakly references us via - # this closure. When the monitor is freed, a call to target() raises - # ReferenceError and stops the executor. + # this closure. When the monitor is freed, stop the executor. + self_ref = weakref.ref(self) + def target(): - Monitor._run(weakref.proxy(self)) + monitor = self_ref() + if monitor is None: + return False # Stop the executor. + Monitor._run(monitor) + return True self._executor = periodic_executor.PeriodicExecutor( condition_class=self._settings.condition_class, diff --git a/pymongo/periodic_executor.py b/pymongo/periodic_executor.py index 4f80a58ff..6699159d0 100644 --- a/pymongo/periodic_executor.py +++ b/pymongo/periodic_executor.py @@ -26,7 +26,7 @@ class PeriodicExecutor(object): def __init__(self, condition_class, interval, min_interval, target): """"Run a target function periodically on a background thread. - If the function raises an exception, the executor stops. + If the target's return value is false, the executor stops. :Parameters: - `condition_class`: A class like threading.Condition. @@ -84,11 +84,12 @@ class PeriodicExecutor(object): def _run(self): while not self._stopped: try: - self._target() - except Exception: - # It's the target's responsibility to report errors. + if not self._target(): + self._stopped = True + break + except: self._stopped = True - break + raise # Avoid running too frequently if wake() is called very often. time.sleep(self._min_interval)