Bookmark and Share

With ZpCron you can schedule cron-like tasks on Zope. Unfortunately it has a buggy and erroneous crontab parser we have to fix.

  1. At first make sure to get the revised version of ZpCron.
  2. Create a file named cron.py within the ZpCron products folder and insert the code from CrontabSchedulerForPython.
  3. Now we have to patch some files of ZpCron:

crontab.py (This patch fixes the crontab parser and time calculator)

--- crontab.py 
+++ crontab_patched.py 
@@ -16,8 +16,7 @@
 
 import time
 import datetime
-import calendar
-import sys
+from cron import SimpleCrontab
 import bisect
 
 class CronTab(object):
@@ -59,42 +58,8 @@
         return command
     ### </override this> ###
     
-    def getMinMax(self, times, type):
-#        if type == 2:
-#            monthmax = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
-#            month = times[3]
-#            return 1, monthmax[month]
-#        else:
-        minmax = ((0, 59), (0, 23), (1, 29), (1, 12), (0, 7))
-        return minmax[type]
-    
     def normalizeTimes(self, times):
-        ret = []
-        for type, t1 in enumerate(times):
-            min, max = self.getMinMax(ret, type)
-            x = []
-            for t in t1.split(','):
-                t = t.split('/')
-                if len(t) > 1:
-                    interval = int(t[1])
-                else:
-                    interval = 1
-                if t[0] == '*':
-                    x.extend(range(min, max, interval))
-                else:
-                    t = t[0].split('-')
-                    if len(t) > 1:
-                        x.extend(range(int(t[0]), int(t[1])+1, interval))
-                    else:
-                        x.append(int(t[0]))
-            x = list(set(x))
-            x.sort()
-            ret.append(x)
-        tmp = ret[-1]
-        ret[-1] = set()
-        for i in tmp:
-            ret[-1].add((i+6)%7)
-        return ret
+        return SimpleCrontab(times, None)
     
     def addLine(self, extime, cmd, now = None):
         if now is None:
@@ -137,36 +102,7 @@
     def calculateNextTime(self, extime, now = None):
         if now is None:
             now = time.time()
-        year, mon, day, hour, min, sec, wday, yday, isdst = time.localtime(now)
-        MIN, HOUR, DAY, MON, WDAY = extime
-        for i in MIN:
-            if i > min:
-                min = i
-                break
-        else:
-            min = MIN[0]
-            for i in HOUR:
-                if i > hour:
-                    hour = i
-                    break
-            else:
-                hour = HOUR[0]
-                while True:
-                    for i in DAY:
-                        if i > day:
-                            day = i
-                            break
-                    else:
-                        day = DAY[0]
-                        for i in MON:
-                            if i > mon:
-                                mon = i
-                                break
-                        else:
-                            mon = MON[0]
-                    if calendar.weekday(year, mon, day) in WDAY:
-                        break
-        return time.mktime((year, mon, day, hour, min, 0, wday, -1, -1))
+        return extime.next_run(now)
     
     def getFirstEvents(self, now = None):
         if now is None:

Product.py (This patch fixes an infinite timer recursion when updating the crontab and adds support for transactions)

--- Product.py 
+++ Product_patched.py 
@@ -85,12 +85,12 @@
         
         self.reset()
         self.parseFile(cStringIO.StringIO(self.crontab))
-        if timerObject is not None:
-            timerObject.change()
+        self.restart()
     
     # execution
     @staticmethod
     def tick():
+        import transaction
         from Zope2 import DB
         conn = DB.open()
         
@@ -125,13 +125,16 @@
             obj = app.restrictedTraverse(url)
             output = None
             try:
+                transaction.begin()
                 output = obj(**dict(params))
+                transaction.commit()
             except:
                 exc, val, trac = sys.exc_info()
                 try:
                     output = zpublisher_exception_hook(obj, app.REQUEST, exc, val, trac)
                 except:
                     pass
+                transaction.abort()
             if output:
                 ret.append(output)

Done.

Can I
  help you?


Just drop me a line at
giraffe@joonis.de