FixedIntervalLoopingCall

本文介绍如何使用FixedIntervalLoopingCall在Nova项目中实现周期性的任务执行。通过详细解析源码,展示了如何启动、控制及停止周期性任务,并解释了其中关键函数的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在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
		
		


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值