Add FixedIntervalWithTimeoutLoopingCall
Currently when using FixedIntervalLoopingCall, folks need to add timeout checking logic in their function if they need it. Adding a new class FixedIntervalWithTimeoutLoopingCall to provide timeout checking support will save those effort. Change-Id: I78bfb9e259c2394137d7efbc0ee96bb18a6dc5e7
This commit is contained in:
		@@ -17,6 +17,7 @@
 | 
			
		||||
 | 
			
		||||
import random
 | 
			
		||||
import sys
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
from eventlet import event
 | 
			
		||||
from eventlet import greenthread
 | 
			
		||||
@@ -180,6 +181,37 @@ class FixedIntervalLoopingCall(LoopingCallBase):
 | 
			
		||||
                           stop_on_exception=stop_on_exception)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FixedIntervalWithTimeoutLoopingCall(LoopingCallBase):
 | 
			
		||||
    """A fixed interval looping call with timeout checking mechanism."""
 | 
			
		||||
 | 
			
		||||
    _RUN_ONLY_ONE_MESSAGE = _("A fixed interval looping call with timeout"
 | 
			
		||||
                              " checking and can only run one function at"
 | 
			
		||||
                              " at a time")
 | 
			
		||||
 | 
			
		||||
    _KIND = _('Fixed interval looping call with timeout checking.')
 | 
			
		||||
 | 
			
		||||
    def start(self, interval, initial_delay=None,
 | 
			
		||||
              stop_on_exception=True, timeout=0):
 | 
			
		||||
        start_time = time.time()
 | 
			
		||||
 | 
			
		||||
        def _idle_for(result, elapsed):
 | 
			
		||||
            delay = round(elapsed - interval, 2)
 | 
			
		||||
            if delay > 0:
 | 
			
		||||
                func_name = reflection.get_callable_name(self.f)
 | 
			
		||||
                LOG.warning(_LW('Function %(func_name)r run outlasted '
 | 
			
		||||
                                'interval by %(delay).2f sec'),
 | 
			
		||||
                            {'func_name': func_name, 'delay': delay})
 | 
			
		||||
            elapsed_time = time.time() - start_time
 | 
			
		||||
            if timeout > 0 and elapsed_time > timeout:
 | 
			
		||||
                raise LoopingCallTimeOut(
 | 
			
		||||
                    _('Looping call timed out after %.02f seconds')
 | 
			
		||||
                    % elapsed_time)
 | 
			
		||||
            return -delay if delay < 0 else 0
 | 
			
		||||
 | 
			
		||||
        return self._start(_idle_for, initial_delay=initial_delay,
 | 
			
		||||
                           stop_on_exception=stop_on_exception)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicLoopingCall(LoopingCallBase):
 | 
			
		||||
    """A looping call which sleeps until the next known event.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -180,6 +180,15 @@ class LoopingCallTestCase(test_base.BaseTestCase):
 | 
			
		||||
                       (i, expected, actual))
 | 
			
		||||
            self.assertAlmostEqual(expected, actual, message=message)
 | 
			
		||||
 | 
			
		||||
    def test_looping_call_timed_out(self):
 | 
			
		||||
 | 
			
		||||
        def _fake_task():
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(_fake_task)
 | 
			
		||||
        self.assertRaises(loopingcall.LoopingCallTimeOut,
 | 
			
		||||
                          timer.start(interval=0.1, timeout=0.3).wait)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicLoopingCallTestCase(test_base.BaseTestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
features:
 | 
			
		||||
  - |
 | 
			
		||||
    Add a new type of looping call: FixedIntervalWithTimeoutLoopingCall. It is
 | 
			
		||||
    a FixedIntervalLoopingCall with timeout checking.
 | 
			
		||||
		Reference in New Issue
	
	Block a user