empty
empty

Reputation: 5434

Running Python schedule daily at random times

How do I run a scheduled job at random times daily starting with today? I want to use the schedule package.

pip install schedule

import schedule

def job()
   print("foo")
   return schedule.CancelJob

while True:
   time_str = '{:02d}:{:02d}'.format(random.randint(6, 10), random.randint(0, 59))
   print("Scheduled for {}".format(time_str))
   schedule.every().day.at(time_str).do(job)
   schedule.run_pending()

The above code just spins:

Scheduled for 06:36
Scheduled for 10:00
Scheduled for 06:18

Upvotes: 1

Views: 2663

Answers (1)

jacob
jacob

Reputation: 1097

You're providing a moving target by putting your random time generator inside you while loop. Specifically, after reviewing the source code here, it is clear that the job will only run if datetime.datetime.now() >= self.next_run is true (see scheduler.run_pending() and job.should_run() definitions). Because you are always moving job.next_run, you will only hit it if it happens to be in the past on that particular iteration of the loop. Interestingly, I think this would cause a bug where the probability of actually running your job increases as you approach 24:00, though this has yet to be shown. I think you need to create a separate function for generating the next random time, and call it from your job function. For example:

import schedule
import time
import random

def job():
   print("foo")
   schedule_next_run()
   return schedule.CancelJob

def schedule_next_run():
   time_str = '{:02d}:{:02d}'.format(random.randint(6, 10), random.randint(0, 59))
   schedule.clear()
   print("Scheduled for {}".format(time_str))
   schedule.every().day.at(time_str).do(job)

schedule_next_run()

while True:
   schedule.run_pending()
   time.sleep(60)

Note that the example may not be random for the day that the job starts, as your random time may be before the time you happen to start your script. You could work in a way to pick a random time in the future on the first day to circumvent this as needed.

To verify the above example, I used shorter time spans. The following works for me:

import schedule
import time
import random

def job():
   print("foo")
   schedule_next_run()
   return schedule.CancelJob

def schedule_next_run():
   time_span = random.randint(1, 5)
   schedule.clear()
   print(f'Scheduled in {time_span} seconds')
   schedule.every(time_span).seconds.do(job)

schedule_next_run()

while True:
   schedule.run_pending()

Upvotes: 3

Related Questions