def __init__(self, interval): """ Set up the ticker """ self.interval = interval self.subscriptions = {} # set up a twisted asynchronous repeat call self.task = ExtendedLoopingCall(self._callback)
class Ticker(object): """ Represents a repeatedly running task that calls hooks repeatedly. Overload _callback to change the way it operates. """ @inlineCallbacks def _callback(self): """ This will be called repeatedly every self.interval seconds. self.subscriptions contain tuples of (obj, args, kwargs) for each subscribing object. If overloading, this callback is expected to handle all subscriptions when it is triggered. It should not return anything and should not traceback on poorly designed hooks. The callback should ideally work under @inlineCallbacks so it can yield appropriately. """ for key, (obj, args, kwargs) in self.subscriptions.items(): hook_key = yield kwargs.get("hook_key", "at_tick") if not obj: # object was deleted between calls self.validate() continue try: yield _GA(obj, hook_key)(*args, **kwargs) except Exception: log_trace() def __init__(self, interval): """ Set up the ticker """ self.interval = interval self.subscriptions = {} # set up a twisted asynchronous repeat call self.task = ExtendedLoopingCall(self._callback) def validate(self, start_delay=None): """ Start/stop the task depending on how many subscribers we have using it. """ subs = self.subscriptions if None in subs.values(): # clean out objects that may have been deleted subs = dict((store_key, obj) for store_key, obj in subs if obj) self.subscriptions = subs if self.task.running: if not subs: self.task.stop() elif subs: #print "starting with start_delay=", start_delay self.task.start(self.interval, now=False, start_delay=start_delay) def add(self, store_key, obj, *args, **kwargs): """ Sign up a subscriber to this ticker. If kwargs contains a keyword _start_delay, this will be used to delay the start of the trigger instead of interval. """ start_delay = kwargs.pop("_start_delay", None) self.subscriptions[store_key] = (obj, args, kwargs) self.validate(start_delay=start_delay) def remove(self, store_key): """ Unsubscribe object from this ticker """ self.subscriptions.pop(store_key, False) self.validate() def stop(self): """ Kill the Task, regardless of subscriptions """ self.subscriptions = {} self.validate()