週期性任務在各個模塊的manager.py(computer,scheduler,cell,network)中添加。
添加方法:在模塊manager類實現中添加方法,並用裝飾器periodic_task.periodic_task裝飾。app
以ComputerManager類爲例。dom
在資源上報方法爲例,裝飾器指定該方法爲週期性任務,並經過spacing參數指定任務執行間隔,不指定spacing參數則默認爲60.0s。
nova.computer.manager.ComputerManager
spa
@periodic_task.periodic_task(spacing=CONF.update_resources_interval)
def update_available_resource
…
periodic_task裝飾器指明方法是週期性任務,並給週期性方法增長一些屬性,包括週期型任務名稱,任務執行間隔等。debug
oslo_service.periodic_task.periodic_task
rest
def periodic_task(*args, **kwargs):
...
nova.computer.manager.ComputerManager
nova.manager.Manager
nova.manager.PeriodicTask
oslo_service.periodic_task.PeriodicTask
PeriodicTask類對象經過元類PeriodicTasksMeta建立。
code
@six.add_metaclass(_PeriodicTasksMeta)
class PeriodicTasks(object):
...
PeriodicTasksMeta元類收集模塊manager類中定義的週期性任務,並保存在_periodic_tasks列表中。
oslo_service.PeriodicTasksMeta
對象
blog
DEFAULT_INTERVAL = 60.0
class _PeriodicTasksMeta(type):
def _add_periodic_task(cls, task):
"""Add a periodic task to the list of periodic tasks.
The task should already be decorated by @periodic_task.
:return: whether task was actually enabled
"""
name = task._periodic_name
…
if task._periodic_spacing == 0:
task._periodic_spacing = DEFAULT_INTERVAL
cls._periodic_tasks.append((name, task))
cls._periodic_spacing[name] = task._periodic_spacing
return Truedef init(cls, names, bases, dict_):
"""Metaclass that allows us to collect decorated periodic tasks."""
…
for value in cls.__dict__.values():
if getattr(value, '_periodic_task', False):
cls._add_periodic_task(value)
Computer進程啓動時調用service的start方法,start方法中建立定時器,定時執行periodic_tasks方法。
一、nova.service.Service.
繼承
class Service(service.Service):
"""Service object for binaries running on hosts.
def start(self):
…
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)
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)
class Manager(base.Base, PeriodicTasks):
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)
class PeriodicTasks(object): def run_periodic_tasks(self, context, raise_on_error=False): """Tasks to be run at a periodic interval.""" idle_for = DEFAULT_INTERVAL for task_name, task in self._periodic_tasks: if (task._periodic_external_ok and not self.conf.run_external_periodic_tasks): continue cls_name = reflection.get_class_name(self, fully_qualified=False) full_task_name = '.'.join([cls_name, task_name]) spacing = self._periodic_spacing[task_name] last_run = self._periodic_last_run[task_name] # Check if due, if not skip idle_for = min(idle_for, spacing) if last_run is not None: delta = last_run + spacing - now() if delta > 0: idle_for = min(idle_for, delta) continue LOG.debug("Running periodic task %(full_task_name)s", {"full_task_name": full_task_name}) self._periodic_last_run[task_name] = _nearest_boundary( last_run, spacing) try: task(self, context) except Exception: if raise_on_error: raise LOG.exception(_LE("Error during %(full_task_name)s"), {"full_task_name": full_task_name}) time.sleep(0) return idle_for