Switched Scripts to use ExtendedLoopingCall.

This commit is contained in:
Griatch 2014-02-13 21:04:59 +01:00
parent 854a452f03
commit 9f2433b9c2
2 changed files with 61 additions and 102 deletions

View file

@ -33,9 +33,9 @@ class BodyFunctions(Script):
a random check here so as to only return 33% of the time. a random check here so as to only return 33% of the time.
""" """
if random.random() < 0.66: #if random.random() < 0.66:
# no message this time # # no message this time
return # return
rand = random.random() rand = random.random()
# return a random message # return a random message
if rand < 0.1: if rand < 0.1:

View file

@ -5,8 +5,7 @@ scripts are inheriting from.
It also defines a few common scripts. It also defines a few common scripts.
""" """
from time import time from twisted.internet.defer import Deferred, maybeDeferred
from twisted.internet.defer import maybeDeferred, Deferred
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@ -23,9 +22,6 @@ _SESSIONS = None
_ATTRIBUTE_CACHE_MAXSIZE = settings.ATTRIBUTE_CACHE_MAXSIZE _ATTRIBUTE_CACHE_MAXSIZE = settings.ATTRIBUTE_CACHE_MAXSIZE
def test():
print "Called: %s " % time()
class ExtendedLoopingCall(LoopingCall): class ExtendedLoopingCall(LoopingCall):
""" """
LoopingCall that can start at a delay different LoopingCall that can start at a delay different
@ -52,10 +48,12 @@ class ExtendedLoopingCall(LoopingCall):
if interval < 0: if interval < 0:
raise ValueError, "interval must be >= 0" raise ValueError, "interval must be >= 0"
self.running = True
d = self.deferred = Deferred() d = self.deferred = Deferred()
self.starttime = self.clock.seconds() self.starttime = self.clock.seconds()
self._lastTime = self.starttime self._expectNextCallAt = self.starttime
self.interval = interval self.interval = interval
self._runAtStart = now
if repeats and repeats > 0: if repeats and repeats > 0:
self.repeats = int(repeats) self.repeats = int(repeats)
@ -92,20 +90,6 @@ class ExtendedLoopingCall(LoopingCall):
self.start_delay = None self.start_delay = None
super(ExtendedLoopingCall, self)._reschedule() super(ExtendedLoopingCall, self)._reschedule()
def reset(self, force_call=True):
"""
Reset the loop timer. The task must already be started.
force_call - trigger the callback function
"""
assert self.running, ("Tried to reset a LoopingCall that was "
"not running.")
if self.call is not None:
self.call.cancel()
if force_call:
self()
else:
self._reschedule()
def next_call_time(self): def next_call_time(self):
""" """
@ -113,20 +97,13 @@ class ExtendedLoopingCall(LoopingCall):
start_delay into account. start_delay into account.
""" """
currentTime = self.clock.seconds() currentTime = self.clock.seconds()
if self.start_delay is not None: return self._expectNextCallAt - currentTime
# take start_delay into account
untilNextTime = (self._lastTime - currentTime) % self.start_delay
return max(self._lastTime + self.start_delay, currentTime + untilNextTime)
else:
untilNextTime = (self._lastTime - currentTime) % self.interval
return max(self._lastTime + self.interval, currentTime + untilNextTime)
# #
# Base script, inherit from Script below instead. # Base script, inherit from Script below instead.
# #
class ScriptClass(TypeClass): class ScriptBase(TypeClass):
""" """
Base class for scripts. Don't inherit from this, inherit Base class for scripts. Don't inherit from this, inherit
from the class 'Script' instead. from the class 'Script' instead.
@ -143,31 +120,31 @@ class ScriptClass(TypeClass):
except Exception: except Exception:
return False return False
def _start_task(self, start_now=True): def _start_task(self):
"start task runner" "start task runner"
self.ndb.twisted_task = LoopingCall(self._step_task) self.ndb._task = ExtendedLoopingCall(self._step_task)
if self.ndb._paused_time: if self.ndb._paused_time:
# we had paused the script, restarting # the script was paused; restarting
#print " start with paused time:", self.key, self.ndb._paused_time self.ndb._task.start(self.dbobj.db_interval,
self.ndb.twisted_task.start(self.ndb._paused_time, now=False) now=False,
start_delay=self.ndb._paused_time,
repeats=self.dbobj.db_repeats)
del self.ndb._paused_time
else: else:
# starting script anew. # starting script anew
#print "_start_task: self.interval:", self.key, self.dbobj.interval self.ndb._task.start(self.dbobj.db_interval,
self.ndb.twisted_task.start(self.dbobj.interval, now=self.dbobj.db_start_delay,
now=start_now and not self.start_delay) repeats=self.dbobj.db_repeats)
self.ndb.time_last_called = int(time())
def _stop_task(self): def _stop_task(self):
"stop task runner" "stop task runner"
try: task = self.ndb._task
#print "stopping twisted task:", id(self.ndb.twisted_task), self.obj if task and task.running:
if self.ndb.twisted_task and self.ndb.twisted_task.running: task.stop()
self.ndb.twisted_task.stop()
except Exception:
logger.log_trace()
def _step_err_callback(self, e): def _step_errback(self, e):
"callback for runner errors" "callback for runner errors"
cname = self.__class__.__name__ cname = self.__class__.__name__
estring = _("Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'.") % \ estring = _("Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'.") % \
@ -179,38 +156,27 @@ class ScriptClass(TypeClass):
pass pass
logger.log_errmsg(estring) logger.log_errmsg(estring)
def _step_succ_callback(self): def _step_callback(self):
"step task runner. No try..except needed due to defer wrap." "step task runner. No try..except needed due to defer wrap."
if not self.is_valid(): if not self.is_valid():
self.stop() self.stop()
return return
self.at_repeat()
repeats = self.dbobj.db_repeats
if repeats <= 0:
pass # infinite repeat
elif repeats == 1:
self.stop()
return
else:
self.dbobj.db_repeats -= 1
self.ndb.time_last_called = int(time())
self.save()
if self.ndb._paused_time: # call hook
# this means we were running an unpaused script, for the self.at_repeat()
# time remaining after the pause. Now we start a normal-running
# timer again. repeats = self.ndb._task.repeats
# print "switching to normal run:", self.key if repeats is not None:
del self.ndb._paused_time if repeats <= 0:
self._stop_task() self.stop()
self._start_task(start_now=False) else:
self.dbobj.repeats = repeats
def _step_task(self): def _step_task(self):
"step task" "step task"
try: try:
d = maybeDeferred(self._step_succ_callback) return maybeDeferred(self._step_callback).addErrback(self._step_errback)
d.addErrback(self._step_err_callback)
return d
except Exception: except Exception:
logger.log_trace() logger.log_trace()
@ -224,14 +190,12 @@ class ScriptClass(TypeClass):
system; it's only here for the user to be able to system; it's only here for the user to be able to
check in on their scripts and when they will next be run. check in on their scripts and when they will next be run.
""" """
try: task = self.ndb._task
if self.ndb._paused_time: if task:
return max(0, (self.ndb.time_last_called + self.ndb._paused_time) - int(time())) return int(task.next_call_time())
else:
return max(0, (self.ndb.time_last_called + self.dbobj.db_interval) - int(time()))
except Exception:
return None return None
def start(self, force_restart=False): def start(self, force_restart=False):
""" """
Called every time the script is started (for Called every time the script is started (for
@ -243,6 +207,7 @@ class ScriptClass(TypeClass):
returns 0 or 1 to indicated the script has been started or not. returns 0 or 1 to indicated the script has been started or not.
Used in counting. Used in counting.
""" """
#print "Script %s (%s) start (active:%s, force:%s) ..." % (self.key, id(self.dbobj), #print "Script %s (%s) start (active:%s, force:%s) ..." % (self.key, id(self.dbobj),
# self.is_active, force_restart) # self.is_active, force_restart)
@ -292,12 +257,7 @@ class ScriptClass(TypeClass):
self.at_stop() self.at_stop()
except Exception: except Exception:
logger.log_trace() logger.log_trace()
if self.dbobj.db_interval > 0:
try:
self._stop_task() self._stop_task()
except Exception:
logger.log_trace("Stopping script %s(%s)" % (self.key, self.dbid))
pass
try: try:
self.dbobj.delete() self.dbobj.delete()
except AssertionError: except AssertionError:
@ -310,9 +270,9 @@ class ScriptClass(TypeClass):
This stops a running script and stores its active state. This stops a running script and stores its active state.
""" """
#print "pausing", self.key, self.time_until_next_repeat() #print "pausing", self.key, self.time_until_next_repeat()
dt = self.time_until_next_repeat() task = self.ndb._task
if dt is None: if task:
return dt = self.ndb._task.next_call_time()
self.db._paused_time = dt self.db._paused_time = dt
self._stop_task() self._stop_task()
@ -322,18 +282,17 @@ class ScriptClass(TypeClass):
""" """
#print "unpausing", self.key, self.db._paused_time #print "unpausing", self.key, self.db._paused_time
dt = self.db._paused_time dt = self.db._paused_time
if dt is None: if dt:
return False
try:
self.dbobj.is_active = True
self.at_start()
self.ndb._paused_time = dt self.ndb._paused_time = dt
self._start_task(start_now=False)
del self.db._paused_time del self.db._paused_time
self.dbobj.is_active = True
try:
self.at_start()
except Exception: except Exception:
logger.log_trace() logger.log_trace()
self.dbobj.is_active = False
return False self._start_task()
return True return True
# hooks # hooks
@ -366,7 +325,7 @@ class ScriptClass(TypeClass):
# Base Script - inherit from this # Base Script - inherit from this
# #
class Script(ScriptClass): class Script(ScriptBase):
""" """
This is the class you should inherit from, it implements This is the class you should inherit from, it implements
the hooks called by the script machinery. the hooks called by the script machinery.