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