summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openstack/common/loopingcall.py64
-rw-r--r--openstack/common/threadgroup.py2
-rw-r--r--tests/unit/test_loopingcall.py8
3 files changed, 63 insertions, 11 deletions
diff --git a/openstack/common/loopingcall.py b/openstack/common/loopingcall.py
index be044d8..3704e8e 100644
--- a/openstack/common/loopingcall.py
+++ b/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/openstack/common/threadgroup.py b/openstack/common/threadgroup.py
index a87497f..3558b73 100644
--- a/openstack/common/threadgroup.py
+++ b/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)
diff --git a/tests/unit/test_loopingcall.py b/tests/unit/test_loopingcall.py
index ef09d2b..f7d21b3 100644
--- a/tests/unit/test_loopingcall.py
+++ b/tests/unit/test_loopingcall.py
@@ -34,14 +34,14 @@ class LoopingCallTestCase(utils.BaseTestCase):
def _raise_it():
raise loopingcall.LoopingCallDone(True)
- timer = loopingcall.LoopingCall(_raise_it)
+ timer = loopingcall.FixedIntervalLoopingCall(_raise_it)
self.assertTrue(timer.start(interval=0.5).wait())
def test_return_false(self):
def _raise_it():
raise loopingcall.LoopingCallDone(False)
- timer = loopingcall.LoopingCall(_raise_it)
+ timer = loopingcall.FixedIntervalLoopingCall(_raise_it)
self.assertFalse(timer.start(interval=0.5).wait())
def _wait_for_zero(self):
@@ -54,7 +54,7 @@ class LoopingCallTestCase(utils.BaseTestCase):
def test_repeat(self):
self.num_runs = 2
- timer = loopingcall.LoopingCall(self._wait_for_zero)
+ timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_zero)
self.assertFalse(timer.start(interval=0.5).wait())
def test_interval_adjustment(self):
@@ -77,7 +77,7 @@ class LoopingCallTestCase(utils.BaseTestCase):
try:
timeutils.set_time_override(timeoverrides)
- timer = loopingcall.LoopingCall(self._wait_for_zero)
+ timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_zero)
timer.start(interval=1.01).wait()
finally:
timeutils.clear_time_override()