def _runloop(self): timer = Timer() timer.start() while not self.service._stop: try: result = self.execute() # On a successful result, notify all blocked futures. # Use pop like this to avoid race conditions. while self.__futures.qsize(): f = self.__futures.get() f.set_result(result) except TryLater: self.n_try_later.increment() continue except Exception as e: # On unhandled exceptions, set the exception on any async # blocked execute calls. while self.__futures.qsize(): f = self.__futures.get() f.set_exception(e) raise self.n_iterations.increment() self.execute_duration_ms.add(timer.elapsed * 1000) to_sleep = self.interval - timer.elapsed if to_sleep > 0: if self.stop_event.wait(to_sleep): return else: self.n_slow_iterations.increment() timer.start()
def __init__(self, attempt=1, item=None, deferred=None, future=None): self.attempt = attempt self.item = item self.deferred = deferred self.future = future self.running = threading.Event() self.timer = Timer()
def testInstance(self): t = Timer() # Mock the timestamp to some fixed value t._time = self.mock.Mock() t._time.return_value = 100.0 # Start the timer. Elapsed should remain 0.0 before and after start self.assertEqual(t.elapsed, 0.0) t.start() self.assertEqual(t.elapsed, 0.0) # Make sure running time is 5s t._time.return_value = 105.0 self.assertEqual(t.elapsed, 5.0) # Stop and make sure elapsed time is 5s as well t.stop() self.assertEqual(t.elapsed, 5.0) # Bump time by 5s, but make sure elapsed stays the same t._time.return_value = 110.0 self.assertEqual(t.elapsed, 5.0) # Re-stop the timer, which should update stop_time and elapsed to 10s t.stop() self.assertEqual(t.elapsed, 10.0)
def testContext(self): with Timer() as t: # Mock the timestamp to some fixed value t._time = self.mock.Mock() t._time.return_value = 100.0 # Context manager should have started the timer, so elapsed # should be some big negative number self.assertLess(t.elapsed, 0) # Restart the timer, so we get good data t.start() # Start the timer. Elapsed should remain 0.0 before and after start t.start() self.assertEqual(t.elapsed, 0.0) # Make sure running time is 3s t._time.return_value = 103.0 self.assertEqual(t.elapsed, 3.0) # Bump time again, before exiting t._time.return_value = 105.0 # Stop (via exit) and make sure elapsed time is 5s as well self.assertEqual(t.elapsed, 5.0) # Bump time by 5s, but make sure elapsed stays the same t._time.return_value = 110.0 self.assertEqual(t.elapsed, 5.0) # Re-stop the timer, which should update stop_time and elapsed to 10s t.stop() self.assertEqual(t.elapsed, 10.0)
def test_execute_async(self): f = self.task.execute_async() res = f.result(3.0) self.assertNotNone(res) self.assertGreater(res, 0) # Verify exception path self.task.fail_async = True with self.assertRaises(Exception) as ctx: # Call this twice, since there's a race condition where setting # fail_async and getting the future from execute_async is called # when execute is between the self.fail_async check and the return self.task.execute_async().result(1.0) self.task.execute_async().result(1.0) self.assertEqual(ctx.exception.args[0], "fail_async") # Wait until task shuts down with Timer() as t: while t.elapsed < 5.0: if not self.task.running: break self.assertFalse(self.task.running) # Verify early exception on async_execute against shutdown tasks f = self.task.execute_async() with self.assertRaises(Exception) as ctx: f.result() self.assertEqual(ctx.exception.args[0], "Worker not running")
def _runloop(self): timer = Timer() timer.start() while not self.service._stop: try: self.execute() except TryLater: self.n_try_later.increment() continue self.n_iterations.increment() self.execute_duration_ms.add(timer.elapsed * 1000) to_sleep = self.interval - timer.elapsed if to_sleep > 0: if self.stop_event.wait(to_sleep): return else: self.n_slow_iterations.increment() timer.start()
def _runloop(self): timer = Timer() timer.start() while not self.service._stop: try: result = self.execute() # On a successful result, notify all blocked futures. # Use pop like this to avoid race conditions. while self.__futures.qsize(): f = self.__futures.get() f.set_result(result) except TryLater as e: if self._handle_try_later(e): return continue except Exception as e: # On unhandled exceptions, set the exception on any async # blocked execute calls. while self.__futures.qsize(): f = self.__futures.get() f.set_exception(e) raise self.n_iterations.increment() self.execute_duration_ms.add(timer.elapsed * 1000) to_sleep = self.interval - timer.elapsed if to_sleep > 0: if self.stop_event.wait(to_sleep): return else: self.n_slow_iterations.increment() timer.start()
class ExecuteContext(object): """An abstraction used internally by various tasks to track work Encapsulates common metrics for work that can be retried later, hooks for signalling completion, etc""" def __init__(self, attempt=1, item=None, deferred=None, future=None): self.attempt = attempt self.item = item self.deferred = deferred self.future = future self.running = threading.Event() self.timer = Timer() def start(self): """Indicate that execution has started""" if not self.running.is_set(): if self.future is not None: self.future.set_running_or_notify_cancel() self.timer.start() self.running.set() def set_result(self, result): """Indicate that execution has completed""" self.timer.stop() if self.future is not None: self.future.set_result(result) if self.deferred is not None: self.deferred.callback(result) def set_exception(self, exception): """Indicate that execution has failed""" handled = False self.timer.stop() if self.future is not None: self.future.set_exception(exception) if self.deferred is not None: unhandled = [] self.deferred.addErrback(self._unhandledErrback, unhandled) self.deferred.errback(exception) if not unhandled: handled = True return handled @property def elapsed(self): """Convenience property. Returns timer duration.""" return self.timer.elapsed @staticmethod def _unhandledErrback(error, unhandled): """Fallback errback for deferred processing""" unhandled.append(error) return None def __cmp__(self, obj): """Custom comparators for comparing contexts' work `item`s""" lhs, rhs = id(self), obj if isinstance(obj, ExecuteContext): lhs, rhs = self.item, obj.item return cmp(lhs, rhs) def __lt__(self, obj): """Override __lt__ explicitly for priority queue implementations""" assert isinstance(obj, ExecuteContext) return self.item < obj.item def __eq__(self, obj): assert isinstance(obj, ExecuteContext) return self.item == obj.item def __ne__(self, obj): assert isinstance(obj, ExecuteContext) return self.item != obj.item def __gt__(self, obj): assert isinstance(obj, ExecuteContext) return self.item > obj.item
def test_execute_happens(self): with Timer() as t: while self.task.counter <= 0 and t.elapsed < 3.0: time.sleep(0.101) self.assertGreater(self.task.counter, 0)
def test_multi_execute(self): with Timer() as t: while len(self.task.visit_threads) < 5 and t.elapsed < 3.0: time.sleep(0.101) self.assertGreaterEqual(self.task.counter, 5)