Reputation: 80
Im trying to schedule a task with the module "schedule" for every hour. My problem is i need the task to first run then run again every hour.
This code works fine but it waits an hour before initial run
import schedule
import time
def job():
print("This happens every hour")
schedule.every().hour.do(job)
while True:
schedule.run_pending()
I would like to avoid doing this:
import schedule
import time
def job():
print("This happens immediately then every hour")
schedule.every().hour.do(job)
while i == 0:
job()
i = i+1
while i == 1:
schedule.run_pending()
Ideally it would be nice to have a option like this:
schedule.run_pending_now()
Upvotes: 6
Views: 9277
Reputation: 33
Wrote a utility to schedule a job to run once and at a recurring interval. This has an advantage over kicking off the job manually as the first run will happen outside of the main thread.
import schedule
from typing import Callable
def run_once_then_every(initial_delay: int, interval: int, job_func: Callable, *args, **kwargs):
"""
Convenience wrapper to run a job once immediately (with some delay) then at a recurring interval.
* Requires all intervals to be provided in minutes.
* An initial delay of 0 results in the job running within 1 second.
Note that the waiting period for the first periodic interval starts immediately and thus the
interval between an initial call with a delay may be less than the interval between all other
iterations.
Args:
- initial_delay (int): Delay before the first run of the job in minutes.
An initial delay of 0 results in the job running within 1 second.
- interval (int): Period between job recurrences.
- job_func (Callable): The job to execute
- args: args passed through to "job_func"
- kwargs: kwargs passed through to "job_func"
"""
def wrapped_job_func(*args, **kwargs):
"""
Runs job_func once then returns a value indicating the scheduler
should remove the job from its registry preventing future runs.
"""
job_func(*args, **kwargs)
return schedule.CancelJob
# Schedule the first iteration
if initial_delay == 0:
# Close enough to immediate
schedule.every(1).seconds.do(wrapped_job_func, *args, **kwargs)
else:
schedule.every(initial_delay).minutes.do(wrapped_job_func, *args, **kwargs)
# Schedule periodic runs.
schedule.every(interval).minutes.do(job_func, *args, **kwargs)
Upvotes: 1
Reputation: 3543
Actually I don't think that calling the function directly would be so wise, since it will block the thread without the scheduler, right?
I think there is nothing wrong about setting the job to be executed once, and every 30 sec for example like that:
scheduler.add_job(MPOStarter.run, args=ppi_args) # run once, then every 30 sec
scheduler.add_job(MPOStarter.run, "interval", seconds=30, args=ppi_args)
Upvotes: 0
Reputation: 11
If you have many tasks that takes some time to execute and you want to run them independently during start you can use threading
import schedule
import time
def job():
print("This happens every hour")
def run_threaded(task):
job_thread = threading.Thread(target=task)
job_thread.start()
run_threaded(job) #runs job once during start
schedule.every().hour.do(run_threaded, job)
while True:
schedule.run_pending() # Runs every hour, starting one hour from now.
Upvotes: 1
Reputation: 289
To run all jobs regardless if they are scheduled to run or not, use schedule.run_all()
. Jobs are re-scheduled after finishing, just like they would if they were executed using run_pending()
.
def job_1():
print('Foo')
def job_2():
print('Bar')
schedule.every().monday.at("12:40").do(job_1)
schedule.every().tuesday.at("16:40").do(job_2)
schedule.run_all()
# Add the delay_seconds argument to run the jobs with a number
# of seconds delay in between.
schedule.run_all(delay_seconds=10)```
Upvotes: 2
Reputation: 882626
Probably the easiest solution is to just run it immediately as well as scheduling it, such as with:
import schedule
import time
def job():
print("This happens every hour")
schedule.every().hour.do(job)
job() # Runs now.
while True:
schedule.run_pending() # Runs every hour, starting one hour from now.
Upvotes: 9