2

So I have create a cron-like-scheduler as suggested in the answer to the question found here:

How do I get a Cron like scheduler in Python?

But sometimes, if an event occurs, I would like to delete a different event....

How would I create this functionality?....basically, once created, how could I remove an event?

Also....I'm having trouble making events from an event. Basically, my goal here is to use an event to parse a file every hour, which holds the times I would like to do other events....so I'd want to create the new events from within this hourly event.... but they seem to disappear after being created....

Thanks!

Community
  • 1
  • 1
John Snow
  • 35
  • 3
  • likewise...... how could i list all events currently being checked on? – John Snow Jul 20 '12 at 22:58
  • not sure what you mean by "checked on" but the list of events currently in your CronTab class is in `self.events`. I'd suggest splitting this question in two: one for introspection and another one about the missing events – Toote Jul 21 '12 at 02:02
  • ah...I realized the second question i asked will be answered by the solution#1 posted below if I can get that going. So I'll refrain from posting a second question. Thanks! – John Snow Jul 23 '12 at 20:06

1 Answers1

0

It all depends on how you are actually implementing your cronjob running. But if you want events to be able to modify other events I can think of 3 options:

1. Pass a reference to the cron to the function

Your CronTab class must provide a way for events to be able to "inspect" into it. The best option would be to extend keyword arguments with a "cron" argument and pass it through to the function as follows:

class CronTab(object):
    def __init__(self, *events):
        self.events = events
        for event in self.events:
             event.kwargs['cron'] = self
# rest of the calss remains unmodified

Doing that, all functions called from the Crontab running will be passed a "cron" parameter with a reference to the cron that is running it

2. Add a "pre-run" marshal(s)

You extend your CronTab class to execute not only events on a particular schedule but also call other function(s) before those events. Functions that get an instance of the event and must return True for it to be run. If any of them returns something else, the event in question won't run.

A basic (and untested) implementation for that would be:

class CronTab(object):
    def __init__(self, *events, marshalls=None):
        self.events = events
        if marshalls is not None:
            # marshalls must be a list of callables that return True or False
            self.marshalls = marshalls
        else
            self.marshalls = []

    def run(self):
        t=datetime(*datetime.now().timetuple()[:5])
        while 1:
            for e in self.events:
                if all([x(e) for x in self.marshalls]):
                    e.check(t)

            t += timedelta(minutes=1)
            while datetime.now() < t:
                time.sleep((t - datetime.now()).seconds)

There are obviously better ways to implement this. For example, by doing a reduce operation and thus avoiding running all marshalls for all events after one of them already returned False. But this should point you in the right direction.

It may also be easier to implement this if the CronTab class actually did more work than just called the Event's instance check - or at least de-couple the checking of run to actually running the Event - but I didn't want to modify the original code that much.

3. Provide hooks to Events

This is basically the same solution as the one before but a lot more "fine-grained". Instead of just having one list of pre-run marshalls you would have several lists. The exact amount and details you can tailor to your own needs but here would be my take based on your request.

In addition to the general "pre-run marshalls" you can have one such list for each event name. Before running an event, not only you would run all general "pre-run marshalls" but also the ones specific to the event.

One way to implement that is to make the "pre-run marshalls" list into a dictionary of lists and provide a few methods to manage such lists. Something like this:

class CronTab(object):
    def __init__(self, *events, marshalls=None):
        self.events = events
        self.marshalls = dict()
        if marshalls is not None:
            # marshalls must be a list of callables that return True or False
            self.marshalls['__general'] = marshalls
        else
            self.marshalls['__general'] = []

    # event is a string with the name of the event you want to marshall
    # or None if you want to marshall all of them 
    def register(self, callback, event=None):
        if event = None:
            self.marshalls['__general'].append(callback)
        else:
            self.marshalls.setdefault(event, list()).append(callback)

    def run(self):
        t=datetime(*datetime.now().timetuple()[:5])
        while 1:
            for e in self.events:
                if all([x(e) for x in self.marshalls['__general']]) and
                   all([x(e) for x in self.marshalls[e.name]]):
                    # the above assumes e.name exists (not in reference implementation)
                    e.check(t)

        t += timedelta(minutes=1)
        while datetime.now() < t:
            time.sleep((t - datetime.now()).seconds)

In the same way you could add post-run hooks and other weird stuff like that as you see fit.


With regards to your question about the Events disappearing, please show us some code to be able to further troubleshoot the issue.

Toote
  • 3,323
  • 2
  • 19
  • 25
  • Thanks a ton for the reply! I'm trying to implement option 1: on the line "event.kwargs['cron'] = self" I get the error: TypeError: 'tuple' object does not support item assignment – John Snow Jul 23 '12 at 18:05
  • Ah, sorry...new to python, just used a list instead. Thanks for the great response!!!! – John Snow Jul 23 '12 at 22:35