# under the License.
import copy
+import logging
import random
import time
import six
from cinder.openstack.common._i18n import _, _LE, _LI
-from cinder.openstack.common import log as logging
periodic_opts = [
interval of 60 seconds.
2. With arguments:
- @periodic_task(spacing=N [, run_immediately=[True|False]])
+ @periodic_task(spacing=N [, run_immediately=[True|False]]
+ [, name=[None|"string"])
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.
+ starts. If name is not provided, __name__ of function is used.
"""
def decorator(f):
# Test for old style invocation
f._periodic_enabled = False
else:
f._periodic_enabled = kwargs.pop('enabled', True)
+ f._periodic_name = kwargs.pop('name', f.__name__)
# Control frequency
f._periodic_spacing = kwargs.pop('spacing', 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:
+ LOG.info(_LI('Skipping periodic task %(task)s because '
+ 'its interval is negative'),
+ {'task': name})
+ return False
+ if not task._periodic_enabled:
+ LOG.info(_LI('Skipping periodic task %(task)s because '
+ 'it is disabled'),
+ {'task': name})
+ return False
+
+ # A periodic spacing of zero indicates that this task should
+ # be run on the default interval to avoid running too
+ # frequently.
+ if task._periodic_spacing == 0:
+ task._periodic_spacing = DEFAULT_INTERVAL
+
+ cls._periodic_tasks.append((name, task))
+ cls._periodic_spacing[name] = task._periodic_spacing
+ return True
+
def __init__(cls, names, bases, dict_):
"""Metaclass that allows us to collect decorated periodic tasks."""
super(_PeriodicTasksMeta, cls).__init__(names, bases, dict_)
for value in cls.__dict__.values():
if getattr(value, '_periodic_task', False):
- task = value
- name = task.__name__
-
- if task._periodic_spacing < 0:
- LOG.info(_LI('Skipping periodic task %(task)s because '
- 'its interval is negative'),
- {'task': name})
- continue
- if not task._periodic_enabled:
- LOG.info(_LI('Skipping periodic task %(task)s because '
- 'it is disabled'),
- {'task': name})
- continue
-
- # A periodic spacing of zero indicates that this task should
- # be run on the default interval to avoid running too
- # frequently.
- if task._periodic_spacing == 0:
- task._periodic_spacing = DEFAULT_INTERVAL
-
- cls._periodic_tasks.append((name, task))
- cls._periodic_spacing[name] = task._periodic_spacing
+ cls._add_periodic_task(value)
def _nearest_boundary(last_run, spacing):
for name, task in self._periodic_tasks:
self._periodic_last_run[name] = task._periodic_last_run
+ def add_periodic_task(self, task):
+ """Add a periodic task to the list of periodic tasks.
+
+ The task should already be decorated by @periodic_task.
+ """
+ if self.__class__._add_periodic_task(task):
+ self._periodic_last_run[task._periodic_name] = (
+ task._periodic_last_run)
+
def run_periodic_tasks(self, context, raise_on_error=False):
"""Tasks to be run at a periodic interval."""
idle_for = DEFAULT_INTERVAL