summaryrefslogtreecommitdiffstats
path: root/nova/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/utils.py')
-rw-r--r--nova/utils.py59
1 files changed, 53 insertions, 6 deletions
diff --git a/nova/utils.py b/nova/utils.py
index 26468868a..1056a6e2d 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -556,12 +556,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 looping call which happens at a fixed interval."""
def start(self, interval, initial_delay=None):
self._running = True
@@ -581,7 +592,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:
@@ -592,11 +603,47 @@ class LoopingCall(object):
greenthread.spawn(_inner)
return self.done
- def stop(self):
- self._running = False
- def wait(self):
- return self.done.wait()
+class DynamicLoopingCall(LoopingCallBase):
+ """A looping call which happens 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 not periodic_interval_max is None:
+ idle = min(idle, periodic_interval_max)
+ LOG.debug(_('Periodic task processor 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
def xhtml_escape(value):