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

来源:互联网 发布:淘宝会员名怎么改手机 编辑:程序博客网 时间:2024/06/11 13:02
在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的变量并设置成truedef 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_taskclass 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添加一个周期性任务就很简单了

原创粉丝点击