2018-04-19 20:47:21 +02:00
|
|
|
import logging
|
|
|
|
|
|
|
|
log = logging.getLogger()
|
|
|
|
|
|
|
|
MIN_DELAY = 0.0
|
|
|
|
MAX_DELAY = 0.01
|
|
|
|
DELAY_INCREMENT = 0.0001
|
|
|
|
QUEUE_SIZE_THRESHOLD = 100
|
|
|
|
|
|
|
|
|
2018-02-22 17:29:10 +01:00
|
|
|
class CallLaterManager(object):
|
2018-05-24 02:41:01 +02:00
|
|
|
def __init__(self, callLater):
|
|
|
|
"""
|
|
|
|
:param callLater: (IReactorTime.callLater)
|
|
|
|
"""
|
|
|
|
|
|
|
|
self._callLater = callLater
|
|
|
|
self._pendingCallLaters = []
|
|
|
|
self._delay = MIN_DELAY
|
|
|
|
|
|
|
|
def get_min_delay(self):
|
|
|
|
self._pendingCallLaters = [cl for cl in self._pendingCallLaters if cl.active()]
|
|
|
|
queue_size = len(self._pendingCallLaters)
|
2018-04-19 20:47:21 +02:00
|
|
|
if queue_size > QUEUE_SIZE_THRESHOLD:
|
2018-05-24 02:41:01 +02:00
|
|
|
self._delay = min((self._delay + DELAY_INCREMENT), MAX_DELAY)
|
2018-04-19 20:47:21 +02:00
|
|
|
else:
|
2018-05-24 02:41:01 +02:00
|
|
|
self._delay = max((self._delay - 2.0 * DELAY_INCREMENT), MIN_DELAY)
|
|
|
|
return self._delay
|
2018-02-22 17:29:10 +01:00
|
|
|
|
2018-05-24 02:41:01 +02:00
|
|
|
def _cancel(self, call_later):
|
2018-02-22 17:29:10 +01:00
|
|
|
"""
|
|
|
|
:param call_later: DelayedCall
|
|
|
|
:return: (callable) canceller function
|
|
|
|
"""
|
|
|
|
|
|
|
|
def cancel(reason=None):
|
|
|
|
"""
|
|
|
|
:param reason: reason for cancellation, this is returned after cancelling the DelayedCall
|
|
|
|
:return: reason
|
|
|
|
"""
|
|
|
|
|
|
|
|
if call_later.active():
|
|
|
|
call_later.cancel()
|
2018-05-24 02:41:01 +02:00
|
|
|
if call_later in self._pendingCallLaters:
|
|
|
|
self._pendingCallLaters.remove(call_later)
|
2018-02-22 17:29:10 +01:00
|
|
|
return reason
|
|
|
|
return cancel
|
|
|
|
|
2018-05-24 02:41:01 +02:00
|
|
|
def stop(self):
|
2018-02-22 17:29:10 +01:00
|
|
|
"""
|
|
|
|
Cancel any callLaters that are still running
|
|
|
|
"""
|
|
|
|
|
|
|
|
from twisted.internet import defer
|
2018-05-24 02:41:01 +02:00
|
|
|
while self._pendingCallLaters:
|
|
|
|
canceller = self._cancel(self._pendingCallLaters[0])
|
2018-02-22 17:29:10 +01:00
|
|
|
try:
|
|
|
|
canceller()
|
2018-05-24 00:10:23 +02:00
|
|
|
except (defer.CancelledError, defer.AlreadyCalledError, ValueError):
|
2018-02-22 17:29:10 +01:00
|
|
|
pass
|
|
|
|
|
2018-05-24 02:41:01 +02:00
|
|
|
def call_later(self, when, what, *args, **kwargs):
|
2018-02-22 17:29:10 +01:00
|
|
|
"""
|
|
|
|
Schedule a call later and get a canceller callback function
|
|
|
|
|
|
|
|
:param when: (float) delay in seconds
|
|
|
|
:param what: (callable)
|
|
|
|
:param args: (*tuple) args to be passed to the callable
|
|
|
|
:param kwargs: (**dict) kwargs to be passed to the callable
|
|
|
|
|
|
|
|
:return: (tuple) twisted.internet.base.DelayedCall object, canceller function
|
|
|
|
"""
|
|
|
|
|
2018-05-24 02:41:01 +02:00
|
|
|
call_later = self._callLater(when, what, *args, **kwargs)
|
|
|
|
canceller = self._cancel(call_later)
|
|
|
|
self._pendingCallLaters.append(call_later)
|
2018-02-22 17:29:10 +01:00
|
|
|
return call_later, canceller
|
|
|
|
|
2018-05-24 02:41:01 +02:00
|
|
|
def call_soon(self, what, *args, **kwargs):
|
|
|
|
delay = self.get_min_delay()
|
|
|
|
return self.call_later(delay, what, *args, **kwargs)
|