summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAngus Salkeld <asalkeld@redhat.com>2012-07-30 12:24:40 +1000
committerAngus Salkeld <asalkeld@redhat.com>2012-07-31 20:13:53 +1000
commit356c72ea4af021078aaf5beeba411322a9a93d1f (patch)
tree386d5a0ebcd5601bd1141d83893236b83f3b93bb
parente0134fc3e2d7e59741b3643e2680f578cc9def41 (diff)
downloadoslo-356c72ea4af021078aaf5beeba411322a9a93d1f.tar.gz
oslo-356c72ea4af021078aaf5beeba411322a9a93d1f.tar.xz
oslo-356c72ea4af021078aaf5beeba411322a9a93d1f.zip
Copy LoopingCall from nova for service.py
Change-Id: Ib6683324f92345c17cfd7234d08070b48ffb4d3e Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
-rw-r--r--openstack/common/loopingcall.py88
-rw-r--r--tests/unit/test_loopingcall.py52
2 files changed, 140 insertions, 0 deletions
diff --git a/openstack/common/loopingcall.py b/openstack/common/loopingcall.py
new file mode 100644
index 0000000..ede3dae
--- /dev/null
+++ b/openstack/common/loopingcall.py
@@ -0,0 +1,88 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import sys
+
+from eventlet import event
+from eventlet import greenthread
+
+from openstack.common import log as logging
+from openstack.common.gettextutils import _
+
+LOG = logging.getLogger(__name__)
+
+
+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, initial_delay=None):
+ self._running = True
+ done = event.Event()
+
+ def _inner():
+ if initial_delay:
+ greenthread.sleep(initial_delay)
+
+ 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/tests/unit/test_loopingcall.py b/tests/unit/test_loopingcall.py
new file mode 100644
index 0000000..11aa7e3
--- /dev/null
+++ b/tests/unit/test_loopingcall.py
@@ -0,0 +1,52 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import unittest
+
+from openstack.common import loopingcall
+
+
+class LoopingCallTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.num_runs = 0
+
+ def test_return_true(self):
+ def _raise_it():
+ raise loopingcall.LoopingCallDone(True)
+
+ timer = loopingcall.LoopingCall(_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)
+ self.assertFalse(timer.start(interval=0.5).wait())
+
+ def test_repeat(self):
+ self.num_runs = 2
+
+ def _wait_for_zero():
+ """Called at an interval until num_runs == 0."""
+ if self.num_runs == 0:
+ raise loopingcall.LoopingCallDone(False)
+ else:
+ self.num_runs = self.num_runs - 1
+
+ timer = loopingcall.LoopingCall(_wait_for_zero)
+ self.assertFalse(timer.start(interval=0.5).wait())