Merge "sync periodic_task fix from incubator"

This commit is contained in:
Jenkins 2014-07-25 12:55:06 +00:00 committed by Gerrit Code Review
commit 4c22c8cb28

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import random
import time import time
from oslo.config import cfg from oslo.config import cfg
@ -80,14 +81,14 @@ def periodic_task(*args, **kwargs):
return f return f
# NOTE(sirp): The `if` is necessary to allow the decorator to be used with # NOTE(sirp): The `if` is necessary to allow the decorator to be used with
# and without parents. # and without parenthesis.
# #
# In the 'with-parents' case (with kwargs present), this function needs to # In the 'with-parenthesis' case (with kwargs present), this function needs
# return a decorator function since the interpreter will invoke it like: # to return a decorator function since the interpreter will invoke it like:
# #
# periodic_task(*args, **kwargs)(f) # periodic_task(*args, **kwargs)(f)
# #
# In the 'without-parents' case, the original function will be passed # In the 'without-parenthesis' case, the original function will be passed
# in as the first argument, like: # in as the first argument, like:
# #
# periodic_task(f) # periodic_task(f)
@ -142,6 +143,27 @@ class _PeriodicTasksMeta(type):
cls._periodic_spacing[name] = task._periodic_spacing cls._periodic_spacing[name] = task._periodic_spacing
def _nearest_boundary(last_run, spacing):
"""Find nearest boundary which is in the past, which is a multiple of the
spacing with the last run as an offset.
Eg if last run was 10 and spacing was 7, the new last run could be: 17, 24,
31, 38...
0% to 5% of the spacing value will be added to this value to ensure tasks
do not synchronize. This jitter is rounded to the nearest second, this
means that spacings smaller than 20 seconds will not have jitter.
"""
current_time = time.time()
if last_run is None:
return current_time
delta = current_time - last_run
offset = delta % spacing
# Add up to 5% jitter
jitter = int(spacing * (random.random() / 20))
return current_time - offset + jitter
@six.add_metaclass(_PeriodicTasksMeta) @six.add_metaclass(_PeriodicTasksMeta)
class PeriodicTasks(object): class PeriodicTasks(object):
def __init__(self): def __init__(self):
@ -159,17 +181,18 @@ class PeriodicTasks(object):
spacing = self._periodic_spacing[task_name] spacing = self._periodic_spacing[task_name]
last_run = self._periodic_last_run[task_name] last_run = self._periodic_last_run[task_name]
# If a periodic task is _nearly_ due, then we'll run it early # Check if due, if not skip
idle_for = min(idle_for, spacing) idle_for = min(idle_for, spacing)
if last_run is not None: if last_run is not None:
delta = last_run + spacing - time.time() delta = last_run + spacing - time.time()
if delta > 0.2: if delta > 0:
idle_for = min(idle_for, delta) idle_for = min(idle_for, delta)
continue continue
LOG.debug("Running periodic task %(full_task_name)s", LOG.debug("Running periodic task %(full_task_name)s",
{"full_task_name": full_task_name}) {"full_task_name": full_task_name})
self._periodic_last_run[task_name] = time.time() self._periodic_last_run[task_name] = _nearest_boundary(
last_run, spacing)
try: try:
task(self, context) task(self, context)