1
# Copyright 2010 United States Government as represented by the
2
# Administrator of the National Aeronautics and Space Administration.
3
# Copyright 2011 Justin Santa Barbara
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
21
from eventlet import event
22
from eventlet import greenthread
24
from sahara.openstack.common.gettextutils import _LE, _LW
25
from sahara.openstack.common import log as logging
27
LOG = logging.getLogger(__name__)
29
# NOTE(zyluo): This lambda function was declared to avoid mocking collisions
30
# with time.time() called in the standard logging module
32
_ts = lambda: time.time()
35
class LoopingCallDone(Exception):
36
"""Exception to break out and stop a LoopingCallBase.
38
The poll-function passed to LoopingCallBase can raise this exception to
39
break out of the loop normally. This is somewhat analogous to
42
An optional return-value can be included as the argument to the exception;
43
this return-value will be returned by LoopingCallBase.wait()
47
def __init__(self, retvalue=True):
48
""":param retvalue: Value that LoopingCallBase.wait() should return."""
49
self.retvalue = retvalue
52
class LoopingCallBase(object):
53
def __init__(self, f=None, *args, **kw):
64
return self.done.wait()
67
class FixedIntervalLoopingCall(LoopingCallBase):
68
"""A fixed interval looping call."""
70
def start(self, interval, initial_delay=None):
76
greenthread.sleep(initial_delay)
81
self.f(*self.args, **self.kw)
85
delay = end - start - interval
87
LOG.warn(_LW('task %(func_name)s run outlasted '
88
'interval by %(delay).2f sec'),
89
{'func_name': repr(self.f), 'delay': delay})
90
greenthread.sleep(-delay if delay < 0 else 0)
91
except LoopingCallDone as e:
95
LOG.exception(_LE('in fixed duration looping call'))
96
done.send_exception(*sys.exc_info())
103
greenthread.spawn_n(_inner)
107
class DynamicLoopingCall(LoopingCallBase):
108
"""A looping call which sleeps until the next known event.
110
The function called should return how long to sleep for before being
114
def start(self, initial_delay=None, periodic_interval_max=None):
120
greenthread.sleep(initial_delay)
124
idle = self.f(*self.args, **self.kw)
125
if not self._running:
128
if periodic_interval_max is not None:
129
idle = min(idle, periodic_interval_max)
130
LOG.debug('Dynamic looping call %(func_name)s sleeping '
131
'for %(idle).02f seconds',
132
{'func_name': repr(self.f), 'idle': idle})
133
greenthread.sleep(idle)
134
except LoopingCallDone as e:
136
done.send(e.retvalue)
138
LOG.exception(_LE('in dynamic looping call'))
139
done.send_exception(*sys.exc_info())
146
greenthread.spawn(_inner)