From 6e65b881c00bfcdea6ef81cc0e3bb06b20299147 Mon Sep 17 00:00:00 2001 From: Michael Still Date: Tue, 9 Apr 2013 15:05:30 +1000 Subject: [PATCH] Update to the latest loopingcall from oslo. This needs threadgroup as well, as it uses loopingcall. Change-Id: Idfa68519c9e263830c9e6a16c2e1bfbd8c89069d --- heat/common/utils.py | 64 ---------------------------- heat/openstack/common/loopingcall.py | 64 +++++++++++++++++++++++++--- heat/openstack/common/threadgroup.py | 2 +- 3 files changed, 59 insertions(+), 71 deletions(-) diff --git a/heat/common/utils.py b/heat/common/utils.py index a36d0c46..b6512110 100644 --- a/heat/common/utils.py +++ b/heat/common/utils.py @@ -20,11 +20,6 @@ System-level utilities and helper functions. """ -import sys - -from eventlet import event -from eventlet import greenthread - from heat.openstack.common import log as logging @@ -55,62 +50,3 @@ def chunkiter(fp, chunk_size=65536): yield chunk else: break - - -class LoopingCallDone(Exception): - """Exception to break out and stop a LoopingCall. - - The poll-function passed to LoopingCall can raise this exception to - break out of the loop normally. This is somewhat analogous to - StopIteration. - - An optional return-value can be included as the argument to the exception; - this return-value will be returned by LoopingCall.wait() - - """ - - def __init__(self, retvalue=True): - """:param retvalue: Value that LoopingCall.wait() should return.""" - self.retvalue = retvalue - - -class LoopingCall(object): - def __init__(self, f=None, *args, **kw): - self.args = args - self.kw = kw - self.f = f - self._running = False - - def start(self, interval, now=True): - self._running = True - done = event.Event() - - def _inner(): - if not now: - greenthread.sleep(interval) - try: - while self._running: - self.f(*self.args, **self.kw) - if not self._running: - break - greenthread.sleep(interval) - except LoopingCallDone, e: - self.stop() - done.send(e.retvalue) - except Exception: - LOG.exception(_('in looping call')) - done.send_exception(*sys.exc_info()) - return - else: - done.send(True) - - self.done = done - - greenthread.spawn(_inner) - return self.done - - def stop(self): - self._running = False - - def wait(self): - return self.done.wait() diff --git a/heat/openstack/common/loopingcall.py b/heat/openstack/common/loopingcall.py index 3d1b4a13..3beef2f8 100644 --- a/heat/openstack/common/loopingcall.py +++ b/heat/openstack/common/loopingcall.py @@ -46,12 +46,23 @@ class LoopingCallDone(Exception): self.retvalue = retvalue -class LoopingCall(object): +class LoopingCallBase(object): def __init__(self, f=None, *args, **kw): self.args = args self.kw = kw self.f = f self._running = False + self.done = None + + def stop(self): + self._running = False + + def wait(self): + return self.done.wait() + + +class FixedIntervalLoopingCall(LoopingCallBase): + """A fixed interval looping call.""" def start(self, interval, initial_delay=None): self._running = True @@ -77,7 +88,7 @@ class LoopingCall(object): self.stop() done.send(e.retvalue) except Exception: - LOG.exception(_('in looping call')) + LOG.exception(_('in fixed duration looping call')) done.send_exception(*sys.exc_info()) return else: @@ -88,8 +99,49 @@ class LoopingCall(object): greenthread.spawn_n(_inner) return self.done - def stop(self): - self._running = False - def wait(self): - return self.done.wait() +# TODO(mikal): this class name is deprecated in Havana and should be removed +# in the I release +LoopingCall = FixedIntervalLoopingCall + + +class DynamicLoopingCall(LoopingCallBase): + """A looping call which sleeps until the next known event. + + The function called should return how long to sleep for before being + called again. + """ + + def start(self, initial_delay=None, periodic_interval_max=None): + self._running = True + done = event.Event() + + def _inner(): + if initial_delay: + greenthread.sleep(initial_delay) + + try: + while self._running: + idle = self.f(*self.args, **self.kw) + if not self._running: + break + + if periodic_interval_max is not None: + idle = min(idle, periodic_interval_max) + LOG.debug(_('Dynamic looping call sleeping for %.02f ' + 'seconds'), idle) + greenthread.sleep(idle) + except LoopingCallDone, e: + self.stop() + done.send(e.retvalue) + except Exception: + LOG.exception(_('in dynamic looping call')) + done.send_exception(*sys.exc_info()) + return + else: + done.send(True) + + self.done = done + + greenthread.spawn(_inner) + return self.done diff --git a/heat/openstack/common/threadgroup.py b/heat/openstack/common/threadgroup.py index fecefbc1..1843e02c 100644 --- a/heat/openstack/common/threadgroup.py +++ b/heat/openstack/common/threadgroup.py @@ -63,7 +63,7 @@ class ThreadGroup(object): def add_timer(self, interval, callback, initial_delay=None, *args, **kwargs): - pulse = loopingcall.LoopingCall(callback, *args, **kwargs) + pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs) pulse.start(interval=interval, initial_delay=initial_delay) self.timers.append(pulse) -- 2.45.2