Seeking ideas for a cron implementation
Karthik Gurusamy
kar1107 at gmail.com
Sun Sep 7 02:14:20 CEST 2008
On Aug 22, 1:51 pm, Sean DiZazzo <half.ital... at gmail.com> wrote:
> On Aug 22, 1:30 pm, Karthik Gurusamy <kar1... at gmail.com> wrote:
>
>
>
> > Hi,
>
> > I'm working on acronlike functionality for my application.
> > The outer loops runs continuously waking every x seconds (say x=180,
> > 300, ..).
> > It needs to know what events incronhas expired and for each event do
> > the work needed.
>
> > It's basically like unixcronor like a calendar application with some
> > restrictions. The outer loop may come back a lot later and many events
> > might have missed their schedule -- but this is okay.. We don't have
> > to worry about missed events (if there were n misses, we just need to
> > execute call back once).
>
> > Let's take some examples [Let e denotes an event]
> > e1: hour=1 min=30 # Run every day once at
> > 1:30 AM
> > e2: wday=0, hour=1 min=0 # run every Monday at 1 AM
> > e3: month=10, day=10, hour=10 min=0 # run on October 10th, 10 AM
> > every year
>
> > class Cron_Event (object):
> > def __init__ (year=None, month=None, day=None, hour=None ..etc)
> > # do init
>
> > classCron(object):
> > def __init__ ():
> > # do init
> > def event_add (e):
> > # add an event
> > def execute()
> > # see if any events has "expired" .. call it's callback
> > # I'm looking for ideas on how to manage the events here
>
> > From outer loop
> >cron=Cron()
> > # create various events like
> > e1 = Cron_Event(hour=1)
> >cron.event_add(e1)
> > e2 = Cron_Event(wday=0, hour=1)
> >cron.event_add(e2)
>
> > while True:
> > sleep x seconds (or wait until woken up)
> > cron.execute()
> > # do other work.. x may change here
>
> > If I can restrict to hour and minute, it seems manageable as the
> > interval between two occurrences is a constant. But allowing days like
> > every Monday or 1st of every month makes things complicated. Moreover
> > I would like each constraint in e to take on multiple possibilities
> > (like every day at 1AM, 2 AM and 4 AM do this).
>
> > I'm looking for solutions that can leverage datetime.datetime
> > routines.
> > My current ideas include for each e, track the next time it will fire
> > (in seconds since epoch as given by time.time()). Once current time
> > has passed that time, we execute the event. e.g.>>> datetime.datetime.now()
>
> > datetime.datetime(2008, 8, 22, 13, 19, 54, 5567)>>> time.time()
>
> > 1219436401.741966 <--- compute event's next firing in a format like
> > this
>
> > The problem seems to be how to compute that future point in time (in
> > seconds since epoch) for a generic Cron_Event.
>
> > Say how do I know the exact time in future that will satisfy a
> > constraint like:
> > month=11, wday=1, hour=3, min=30 # At 3:30 AM on a Tuesday in
> > November
>
> > Thanks for your thoughts.
>
> > Karthik
>
> I only scanned your message, but maybe datetime.timedelta() will
> help..
>
> >>> import datetime
> >>> now = datetime.datetime.now()
> >>> print now
>
> 2008-08-22 13:48:49.335225>>> day = datetime.timedelta(1)
> >>> print day
> 1 day, 0:00:00
> >>> print now + day
>
> 2008-08-23 13:48:49.335225
Thanks, I found using a more efficient algorithm tricky and seemed
error prone.
[I do welcome ideas still if anyone has a cool solution]
I used your idea and took the easy way out by using a brute-force
search.
Here is an outline if anyone faces similar problem:
hours, minutes are lists: say for every day at 1:30 pm and 2:45 pm,
hours=[13, 14] and minutes=[30, 45,].
I restricted myself to minutes and hours (and every day) to simplify
the problem.
def set_expiry_time_check_in_a_day (self, now, target,
hours, mins, flags=set()):
"""
A small utility routine to simulate 'goto'
Looks like now could be computed inside this function --
the small
drift due to time taken in this function should be
negligible
"""
# let's see if in today we can find an expiry
# we do brute force search starting with the smallest hour
for hour in hours:
for min in mins:
target = target.replace(hour=hour, minute=min,
second=0,
microsecond=0)
if 'is_debug_1' in flags:
print "Trying target time: %s..." % target
if target > now:
if 'is_debug_1' in flags:
print "Found target time: %s" % (target, )
return target # simulates a break from two loops
return None
def set_expiry_time (self, event, flags=set()):
"""
For a given event, compute and remember when it will fire
next
"""
now = datetime.datetime.now()
target = now # start checking from now..
# assumption, hours and mins are atleast one int element array
# and they are in sorted order
hours = event.spec['hours']
mins = event.spec['minutes']
tries = 0
while True: # runs of each day.. tomorrow ...
tries += 1
if tries > 50: # safety valve, we are basically in
infinite loop
raise Exception("Tried 50 times.. in infinite loop??")
target_found = self.set_expiry_time_check_in_a_day(now,
target,
hours, mins, flags)
if target_found is not None: # found a match on "this" day
target = target_found
break
# we need to increase the day count..
increment = datetime.timedelta(days=1)
target += increment
# added 24 hours .. let's go and check tomorrow ...
event.target = target
>
> ~Sean
More information about the Python-list
mailing list