Schedule a repeating event in Python 3 Schedule a repeating event in Python 3 python python

Schedule a repeating event in Python 3


You could use threading.Timer, but that also schedules a one-off event, similarly to the .enter method of scheduler objects.

The normal pattern (in any language) to transform a one-off scheduler into a periodic scheduler is to have each event re-schedule itself at the specified interval. For example, with sched, I would not use a loop like you're doing, but rather something like:

def periodic(scheduler, interval, action, actionargs=()):    scheduler.enter(interval, 1, periodic,                    (scheduler, interval, action, actionargs))    action(*actionargs)

and initiate the whole "forever periodic schedule" with a call

periodic(scheduler, 3600, query_rate_limit)

Or, I could use threading.Timer instead of scheduler.enter, but the pattern's quite similar.

If you need a more refined variation (e.g., stop the periodic rescheduling at a given time or upon certain conditions), that's not too hard to accomodate with a few extra parameters.


You could use schedule. It works on Python 2.7 and 3.3 and is rather lightweight:

import scheduleimport timedef job():   print("I'm working...")schedule.every(10).minutes.do(job)schedule.every().hour.do(job)schedule.every().day.at("10:30").do(job)while 1:   schedule.run_pending()   time.sleep(1)


My humble take on the subject:

from threading import Timerclass RepeatedTimer(object):    def __init__(self, interval, function, *args, **kwargs):        self._timer     = None        self.function   = function        self.interval   = interval        self.args       = args        self.kwargs     = kwargs        self.is_running = False        self.start()    def _run(self):        self.is_running = False        self.start()        self.function(*self.args, **self.kwargs)    def start(self):        if not self.is_running:            self._timer = Timer(self.interval, self._run)            self._timer.start()            self.is_running = True    def stop(self):        self._timer.cancel()        self.is_running = False

Usage:

from time import sleepdef hello(name):    print "Hello %s!" % nameprint "starting..."rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()try:    sleep(5) # your long-running job goes here...finally:    rt.stop() # better in a try/finally block to make sure the program ends!

Features:

  • Standard library only, no external dependencies
  • Uses the pattern suggested by Alex Martnelli
  • start() and stop() are safe to call multiple times even if the timer has already started/stopped
  • function to be called can have positional and named arguments
  • You can change interval anytime, it will be effective after next run. Same for args, kwargs and even function!