diff options
author | Michael Still <mikal@stillhq.com> | 2013-04-28 16:51:22 +1000 |
---|---|---|
committer | Michael Still <mikal@stillhq.com> | 2013-05-01 08:45:09 +1000 |
commit | 01b0f6554be87a0664e74c63817c3034ee40a6ac (patch) | |
tree | 7024475a5cb85c767d0d7d784d2508a5c51706c7 /nova/manager.py | |
parent | b7186ce03b43a00c7241be54385120ab3f7a03aa (diff) | |
download | nova-01b0f6554be87a0664e74c63817c3034ee40a6ac.tar.gz nova-01b0f6554be87a0664e74c63817c3034ee40a6ac.tar.xz nova-01b0f6554be87a0664e74c63817c3034ee40a6ac.zip |
Update to using oslo periodic tasks implementation.
Convert nova to using the oslo periodic tasks implementation. There
are no functional changes in this review.
Change-Id: I767e0ad17781d5f9d5e987e0a4ad65796243ae5c
Diffstat (limited to 'nova/manager.py')
-rw-r--r-- | nova/manager.py | 161 |
1 files changed, 4 insertions, 157 deletions
diff --git a/nova/manager.py b/nova/manager.py index 50f26a1b4..2a151827d 100644 --- a/nova/manager.py +++ b/nova/manager.py @@ -53,146 +53,23 @@ This module provides Manager, a base class for managers. """ -import datetime -import eventlet from oslo.config import cfg from nova import baserpc from nova.db import base -from nova import exception from nova.openstack.common import log as logging +from nova.openstack.common import periodic_task from nova.openstack.common.plugin import pluginmanager from nova.openstack.common.rpc import dispatcher as rpc_dispatcher -from nova.openstack.common import timeutils from nova.scheduler import rpcapi as scheduler_rpcapi -periodic_opts = [ - cfg.BoolOpt('run_external_periodic_tasks', - default=True, - help=('Some periodic tasks can be run in a separate process. ' - 'Should we run them here?')), - ] - CONF = cfg.CONF -CONF.register_opts(periodic_opts) CONF.import_opt('host', 'nova.netconf') LOG = logging.getLogger(__name__) -DEFAULT_INTERVAL = 60.0 - - -def periodic_task(*args, **kwargs): - """Decorator to indicate that a method is a periodic task. - - This decorator can be used in two ways: - - 1. Without arguments '@periodic_task', this will be run on every cycle - of the periodic scheduler. - - 2. With arguments: - @periodic_task(spacing=N [, run_immediately=[True|False]]) - this will be run on approximately every N seconds. If this number is - negative the periodic task will be disabled. If the run_immediately - argument is provided and has a value of 'True', the first run of the - task will be shortly after task scheduler starts. If - run_immediately is omitted or set to 'False', the first time the - task runs will be approximately N seconds after the task scheduler - starts. - """ - def decorator(f): - # Test for old style invocation - if 'ticks_between_runs' in kwargs: - raise exception.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) - - # Control frequency - f._periodic_spacing = kwargs.pop('spacing', 0) - f._periodic_immediate = kwargs.pop('run_immediately', False) - if f._periodic_immediate: - f._periodic_last_run = None - else: - f._periodic_last_run = timeutils.utcnow() - return f - - # NOTE(sirp): The `if` is necessary to allow the decorator to be used with - # and without parens. - # - # In the 'with-parens' case (with kwargs present), this function needs to - # return a decorator function since the interpreter will invoke it like: - # - # periodic_task(*args, **kwargs)(f) - # - # In the 'without-parens' case, the original function will be passed - # in as the first argument, like: - # - # periodic_task(f) - if kwargs: - return decorator - else: - return decorator(args[0]) - - -class ManagerMeta(type): - def __init__(cls, names, bases, dict_): - """Metaclass that allows us to collect decorated periodic tasks.""" - super(ManagerMeta, cls).__init__(names, bases, dict_) - - # NOTE(sirp): if the attribute is not present then we must be the base - # class, so, go ahead an initialize it. If the attribute is present, - # then we're a subclass so make a copy of it so we don't step on our - # parent's toes. - try: - cls._periodic_tasks = cls._periodic_tasks[:] - except AttributeError: - cls._periodic_tasks = [] - - try: - cls._periodic_last_run = cls._periodic_last_run.copy() - except AttributeError: - cls._periodic_last_run = {} - - try: - cls._periodic_spacing = cls._periodic_spacing.copy() - except AttributeError: - cls._periodic_spacing = {} - - for value in cls.__dict__.values(): - if getattr(value, '_periodic_task', False): - task = value - name = task.__name__ - - if task._periodic_spacing < 0: - LOG.info(_('Skipping periodic task %(task)s because ' - 'its interval is negative'), - {'task': name}) - continue - if not task._periodic_enabled: - LOG.info(_('Skipping periodic task %(task)s because ' - 'it is disabled'), - {'task': name}) - continue - - # A periodic spacing of zero indicates that this task should - # be run every pass - if task._periodic_spacing == 0: - task._periodic_spacing = None - - cls._periodic_tasks.append((name, task)) - cls._periodic_spacing[name] = task._periodic_spacing - cls._periodic_last_run[name] = task._periodic_last_run - - -class Manager(base.Base): - __metaclass__ = ManagerMeta +class Manager(base.Base, periodic_task.PeriodicTasks): # Set RPC API version to 1.0 by default. RPC_API_VERSION = '1.0' @@ -220,37 +97,7 @@ class Manager(base.Base): def 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: - full_task_name = '.'.join([self.__class__.__name__, task_name]) - - now = timeutils.utcnow() - spacing = self._periodic_spacing[task_name] - last_run = self._periodic_last_run[task_name] - - # If a periodic task is _nearly_ due, then we'll run it early - if spacing is not None and last_run is not None: - due = last_run + datetime.timedelta(seconds=spacing) - if not timeutils.is_soon(due, 0.2): - idle_for = min(idle_for, timeutils.delta_seconds(now, due)) - continue - - if spacing is not None: - idle_for = min(idle_for, spacing) - - LOG.debug(_("Running periodic task %(full_task_name)s"), locals()) - self._periodic_last_run[task_name] = timeutils.utcnow() - - try: - task(self, context) - except Exception as e: - if raise_on_error: - raise - LOG.exception(_("Error during %(full_task_name)s: %(e)s"), - locals()) - eventlet.sleep(0) - - return idle_for + return self.run_periodic_tasks(context, raise_on_error=raise_on_error) def init_host(self): """Hook to do additional manager initialization when one requests @@ -308,7 +155,7 @@ class SchedulerDependentManager(Manager): capabilities = [capabilities] self.last_capabilities = capabilities - @periodic_task + @periodic_task.periodic_task def publish_service_capabilities(self, context): """Pass data back to the scheduler. |