Search code examples
pythonpython-3.xscheduled-tasks

Run a function at the start of every round 5 minute interval


I want to run a function every 5 minutes, it must be at a "round" intervals, for example :

12:05:00, 12:10:00, 12:15:00...

It cannot be like this:

12:06:00, 12:11:00, 12:16:00...

Or like this:

12:05:14, 12:10:14, 12:15:14...

What is the most accurate way to do this in python?


Solution

  • You could use a threading.Timer. You have to do some math to calculate the next run time. datetime has a handy replace method for that.

    from datetime import datetime, timedelta
    from threading import Timer
    from time import sleep
    import random
    
    def schedule_next_run():
        sleep_time = get_sleep_time()
        t = Timer(sleep_time, do_work)
        t.daemon = True
        t.start()
        print(f'sleeping for {sleep_time} seconds')
    
    def get_sleep_time():
        now = datetime.now()
        last_run_time = now.replace(minute=now.minute // 5 * 5, second=0, microsecond=0)
        next_run_time = last_run_time + timedelta(minutes=5)
        return (next_run_time - now).total_seconds()
    
    def do_work():
        now = datetime.now()
        print('Doing some work at', now)
        sleep(random.uniform(0, 29))
        print('Work complete. Scheduling next run.')
        schedule_next_run()
    
    print('Starting work schedule')
    schedule_next_run()
    input('Doing work every 5 minutes. Press enter to exit:\n')
    

    On my system, the function fires within a half millisecond of the target time

    Note that the time calculation rounds down and then adds a timedelta to carefully wrap around the end of each hour. You would want to ponder how this will behave around daylight savings changes.

    Suggestion: move all this logic to a class to clean it up.