With ZpCron you can schedule cron-like tasks on Zope. Unfortunately it has a buggy and erroneous crontab parser we have to fix.
- At first make sure to get the revised version of ZpCron.
- Create a file named cron.py within the ZpCron products folder and insert the code from CrontabSchedulerForPython.
- 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.