在nova中使用FixedIntervalLoopingCall 来实现周期运行的函数的用法如下:
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_destroy,
old_domid)
timer.start(interval=0.5).wait()
首先实例化FixedIntervalLoopingCall 为timer后,就调用timer.start 开始执行,调用timer.wait()等待执行完成
其中FixedIntervalLoopingCall的源码在 https://github.com/openstack/oslo.service/blob/master/oslo_service/loopingcall.py
其分析如下:
#FixedIntervalLoopingCall 实例化的时候其实调用的父类的init函数,
class FixedIntervalLoopingCall(LoopingCallBase):
"""A fixed interval looping call."""
_RUN_ONLY_ONE_MESSAGE = _("A fixed interval looping call can only run"
" one function at a time")
_KIND = _('Fixed interval looping call')
#当调用timer.start 开始执行的时候,首先执行FixedIntervalLoopingCall 类的start,这个start函数中又定义了个子函数,最终start 将子函数作为参数
#传给给_start 函数,这个函数是在父类LoopingCallBase 中实现的,调到父类的_start 看看
def start(self, interval, initial_delay=None, stop_on_exception=True):
def _idle_for(result, elapsed):
delay = round(elapsed - interval, 2)
if delay > 0:
func_name = reflection.get_callable_name(self.f)
LOG.warning('Function %(func_name)r run outlasted '
'interval by %(delay).2f sec',
{'func_name': func_name, 'delay': delay})
return -delay if delay < 0 else 0
return self._start(_idle_for, initial_delay=initial_delay,
stop_on_exception=stop_on_exception)
class LoopingCallBase(object):
_KIND = _("Unknown looping call")
_RUN_ONLY_ONE_MESSAGE = _("A looping call can only run one function"
" at a time")
def __init__(self, f=None, *args, **kw):
self.args = args
self.kw = kw
self.f = f
self._running = False
self._thread = None
self.done = None
def stop(self):
self._running = False
def _on_done(self, gt, *args, **kwargs):
self._thread = None
self._running = False
def _start(self, idle_for, initial_delay=None, stop_on_exception=True):
"""Start the looping
:param idle_for: Callable that takes two positional arguments, returns
how long to idle for. The first positional argument is
the last result from the function being looped and the
second positional argument is the time it took to
calculate that result.
:param initial_delay: How long to delay before starting the looping.
Value is in seconds.
:param stop_on_exception: Whether to stop if an exception occurs.
:returns: eventlet event instance
"""
if self._thread is not None:
raise RuntimeError(self._RUN_ONLY_ONE_MESSAGE)
self._running = True
self.done = event.Event()
#创建一个携程,携程的回调函数是_run_loop
self._thread = greenthread.spawn(
self._run_loop, idle_for,
initial_delay=initial_delay, stop_on_exception=stop_on_exception)
self._thread.link(self._on_done)
return self.done
def _run_loop(self, idle_for_func,
initial_delay=None, stop_on_exception=True):
kind = self._KIND
func_name = reflection.get_callable_name(self.f)
#给func 赋值,本例子中func就等于_wait_for_destroy
func = self.f if stop_on_exception else _safe_wrapper(self.f, kind,
func_name)
if initial_delay:
greenthread.sleep(initial_delay)
try:
watch = timeutils.StopWatch()
while self._running:
watch.restart()
#开始执行_wait_for_destroy函数
result = func(*self.args, **self.kw)
watch.stop()
if not self._running:
break
#这里执行的idle_for_func 是在FixedIntervalLoopingCall 的start函数中定义的delay,这个函数会返回一个值,来决定携程sleep 多久
idle = idle_for_func(result, watch.elapsed())
LOG.trace('%(kind)s %(func_name)r sleeping '
'for %(idle).02f seconds',
{'func_name': func_name, 'idle': idle,
'kind': kind})
greenthread.sleep(idle)
except LoopingCallDone as e:
self.done.send(e.retvalue)
except Exception:
exc_info = sys.exc_info()
try:
LOG.error('%(kind)s %(func_name)r failed',
{'kind': kind, 'func_name': func_name},
exc_info=exc_info)
self.done.send_exception(*exc_info)
finally:
del exc_info
return
else:
self.done.send(True)
最后将调用timer.wait()等待执行完成
这里的wait定义如下:
def wait(self):
return self.done.wait()
这里的done被赋值为event.Event(),执行wait后,会让出当前cpu,让_run_loop函数来执行
而在
def _wait_for_destroy(expected_domid):
"""Called at an interval until the VM is gone."""
# NOTE(vish): If the instance disappears during the destroy
# we ignore it so the cleanup can still be
# attempted because we would prefer destroy to
# never fail.
try:
dom_info = self.get_info(instance)
state = dom_info.state
new_domid = dom_info.internal_id
except exception.InstanceNotFound:
LOG.debug("During wait destroy, instance disappeared.",
instance=instance)
state = power_state.SHUTDOWN
if state == power_state.SHUTDOWN:
LOG.info("Instance destroyed successfully.", instance=instance)
raise loopingcall.LoopingCallDone()
中是通过异常LoopingCallDone 来结束FixedIntervalLoopingCall 的运行的.
class LoopingCallDone(Exception):
"""Exception to break out and stop a LoopingCallBase.
The poll-function passed to LoopingCallBase 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 LoopingCallBase.wait()
"""
def __init__(self, retvalue=True):
""":param retvalue: Value that LoopingCallBase.wait() should return."""
self.retvalue = retvalue
FixedIntervalLoopingCall
最新推荐文章于 2024-05-16 16:06:27 发布