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()
andstop()
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 forargs
,kwargs
and evenfunction
!