通过periodic_task.periodic_task 实现周期性任务的原理

在nova中可以通过添加@periodic_task.periodic_task 来产生一个周期任务。
例如使用默认周期的任务:
    @periodic_task.periodic_task
    def _poll_rebooting_instances(self, context):
        if CONF.reboot_timeout > 0:
            filters = {'task_state':
                       [task_states.REBOOTING,
                        task_states.REBOOT_STARTED,
                        task_states.REBOOT_PENDING],
                       'host': self.host}
            rebooting = objects.InstanceList.get_by_filters(
                context, filters, expected_attrs=[], use_slave=True)

            to_poll = []
            for instance in rebooting:
                if timeutils.is_older_than(instance.updated_at,
                                           CONF.reboot_timeout):
                    to_poll.append(instance)

            self.driver.poll_rebooting_instances(CONF.reboot_timeout, to_poll)
可以自己指定周期任务的时间,这里的周期运行的时间间隔就是CONF.heal_instance_info_cache_interval
    @periodic_task.periodic_task(
        spacing=CONF.heal_instance_info_cache_interval)
    def _heal_instance_info_cache(self, context):
        """Called periodically.  On every call, try to update the
        info_cache's network information for another instance by
        calling to the network manager.

        This is implemented by keeping a cache of uuids of instances
        that live on this host.  On each call, we pop one off of a
        list, pull the DB record, and try the call to the network API.
        If anything errors don't fail, as it's possible the instance
        has been deleted, etc.
        """
        heal_interval = CONF.heal_instance_info_cache_interval
        if not heal_interval:
            return

        instance_uuids = getattr(self, '_instance_uuids_to_heal', [])
        instance = None

        LOG.debug('Starting heal instance info cache')

我们看看def periodic_task(*args, **kwargs):  这个方法就是增加一个_periodic_task的变量并设置成true
def periodic_task(*args, **kwargs):  
    def decorator(f):  
        # Test for old style invocation  
        if 'ticks_between_runs' in kwargs:  
            raise InvalidPeriodicTaskArg(arg='ticks_between_runs')  
  
        # Control if run at all  
        f._periodic_task = True  
        f._periodic_external_ok = kwargs.pop('external_process_ok', False)  
        if f._periodic_external_ok and not CONF.run_external_periodic_tasks:  
            f._periodic_enabled = False  
        else:  
            f._periodic_enabled = kwargs.pop('enabled', True)  

这样在PeriodicTasks 类的PeriodicTasks中会判断是否有_periodic_task,如果有的话,就增加到要周期执行的列表中
 for value in cls.__dict__.values():  
            if getattr(value, '_periodic_task', False):  
                cls._periodic_tasks.append((name, task)) 

这样在PeriodicTasks定义的run_periodic_tasks中就会周期的执行,注意这里用了元类
class PeriodicTasks(object):  
    __metaclass__ = _PeriodicTasksMeta  
  
    def run_periodic_tasks(self, context, raise_on_error=False):  
        ...  
        for task_name, task in self._periodic_tasks:  


这些周期性任务是在nova/service.py 中的class Service(service.Service):类的start函数中被触发的
  def start(self):
        verstr = version.version_string_with_package()
        LOG.info(_LI('Starting %(topic)s node (version %(version)s)'),
                  {'topic': self.topic, 'version': verstr})
          if self.periodic_enable:
            if self.periodic_fuzzy_delay:
                initial_delay = random.randint(0, self.periodic_fuzzy_delay)
            else:
                initial_delay = None

            self.tg.add_dynamic_timer(self.periodic_tasks,
                                     initial_delay=initial_delay,
                                     periodic_interval_max=
                                        self.periodic_interval_max)
可以看到在start函数中添加了一个time。这个time的回调函数是periodic_tasks

    def periodic_tasks(self, raise_on_error=False):
        """Tasks to be run at a periodic interval."""
        ctxt = context.get_admin_context()
        return self.manager.periodic_tasks(ctxt, raise_on_error=raise_on_error)
调用manager.periodic_tasks.这部的代码在nova/manager.pu 中
from oslo_service import periodic_task
class PeriodicTasks(periodic_task.PeriodicTasks):
    def __init__(self):
        super(PeriodicTasks, self).__init__(CONF)
class Manager(base.Base, PeriodicTasks):

    def __init__(self, host=None, db_driver=None, service_name='undefined'):
        if not host:
            host = CONF.host
        self.host = host
        self.backdoor_port = None
        self.service_name = service_name
        self.notifier = rpc.get_notifier(self.service_name, self.host)
        self.additional_endpoints = []
        super(Manager, self).__init__(db_driver)

    def periodic_tasks(self, context, raise_on_error=False):
        """Tasks to be run at a periodic interval."""
        return self.run_periodic_tasks(context, raise_on_error=raise_on_error)
这件最终调用到oslo_service 里面的PeriodicTasks。这个函数在前面分析过了.这样周期性任务就运行起来了
明白了这些道理后,通过periodic_task.periodic_task添加一个周期性任务就很简单了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值