Merge "Make unspecified periodic spaced tasks run on default interval"

This commit is contained in:
Jenkins
2014-05-22 22:46:55 +00:00
committed by Gerrit Code Review
2 changed files with 32 additions and 20 deletions

View File

@@ -44,8 +44,8 @@ def periodic_task(*args, **kwargs):
This decorator can be used in two ways:
1. Without arguments '@periodic_task', this will be run on every cycle
of the periodic scheduler.
1. Without arguments '@periodic_task', this will be run on the default
interval of 60 seconds.
2. With arguments:
@periodic_task(spacing=N [, run_immediately=[True|False]])
@@ -133,9 +133,10 @@ class _PeriodicTasksMeta(type):
continue
# A periodic spacing of zero indicates that this task should
# be run every pass
# be run on the default interval to avoid running too
# frequently.
if task._periodic_spacing == 0:
task._periodic_spacing = None
task._periodic_spacing = DEFAULT_INTERVAL
cls._periodic_tasks.append((name, task))
cls._periodic_spacing[name] = task._periodic_spacing
@@ -159,13 +160,12 @@ class PeriodicTasks(object):
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:
idle_for = min(idle_for, spacing)
if last_run is not None:
delta = last_run + spacing - time.time()
if delta > 0.2:
idle_for = min(idle_for, delta)
continue
idle_for = min(idle_for, spacing)
if last_run is not None:
delta = last_run + spacing - time.time()
if delta > 0.2:
idle_for = min(idle_for, delta)
continue
LOG.debug("Running periodic task %(full_task_name)s",
{"full_task_name": full_task_name})

View File

@@ -45,11 +45,12 @@ class AService(periodic_task.PeriodicTasks):
self.called['urg'] += 1
raise AnException('urg')
@periodic_task.periodic_task(spacing=10, run_immediately=True)
@periodic_task.periodic_task(spacing=10 + periodic_task.DEFAULT_INTERVAL,
run_immediately=True)
def doit_with_ticks(self, context):
self.called['ticks'] += 1
@periodic_task.periodic_task(spacing=10)
@periodic_task.periodic_task(spacing=10 + periodic_task.DEFAULT_INTERVAL)
def doit_with_tocks(self, context):
self.called['tocks'] += 1
@@ -62,31 +63,41 @@ class PeriodicTasksTestCase(test_base.BaseTestCase):
serv = AService()
now = serv._periodic_last_run['doit_with_tocks']
mock_time.return_value = now
time = now + periodic_task.DEFAULT_INTERVAL
mock_time.return_value = time
serv.run_periodic_tasks(None)
self.assertEqual(serv.called['doit'], 1)
self.assertEqual(serv.called['urg'], 1)
self.assertEqual(serv.called['ticks'], 1)
self.assertEqual(serv.called['tocks'], 0)
mock_time.return_value = now + 9
time = time + 9 + periodic_task.DEFAULT_INTERVAL
mock_time.return_value = time
serv.run_periodic_tasks(None)
self.assertEqual(serv.called['doit'], 2)
self.assertEqual(serv.called['urg'], 2)
# doit_with_ticks will only be called the first time because its
# spacing time interval will not have elapsed between the calls.
self.assertEqual(serv.called['ticks'], 1)
self.assertEqual(serv.called['tocks'], 0)
# doit_with_tocks will run since idle_for is equal to DEFAULT_INTERVAL
# and the task processor will pick the minimum of those two to
# determine when to run, and the idle time will have passed.
self.assertEqual(serv.called['tocks'], 1)
mock_time.return_value = now + 10
time = time + 10 + periodic_task.DEFAULT_INTERVAL
mock_time.return_value = time
serv.run_periodic_tasks(None)
self.assertEqual(serv.called['doit'], 3)
self.assertEqual(serv.called['urg'], 3)
self.assertEqual(serv.called['ticks'], 2)
self.assertEqual(serv.called['tocks'], 1)
self.assertEqual(serv.called['tocks'], 2)
def test_raises(self):
@mock.patch('time.time')
def test_raises(self, mock_time):
serv = AService()
now = serv._periodic_last_run['crashit']
mock_time.return_value = now + periodic_task.DEFAULT_INTERVAL
self.assertRaises(AnException,
serv.run_periodic_tasks,
None, raise_on_error=True)
@@ -113,7 +124,8 @@ class ManagerMetaTestCase(test_base.BaseTestCase):
m = Manager()
self.assertThat(m._periodic_tasks, matchers.HasLength(2))
self.assertIsNone(m._periodic_spacing['foo'])
self.assertEqual(periodic_task.DEFAULT_INTERVAL,
m._periodic_spacing['foo'])
self.assertEqual(4, m._periodic_spacing['bar'])
self.assertThat(
m._periodic_spacing, matchers.Not(matchers.Contains('baz')))