Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I schedule an interval job with APScheduler?

I'm trying to schedule an interval job with APScheduler (v3.0.0).

I've tried:

from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()

def my_interval_job():
    print 'Hello World!'
sched.add_job(my_interval_job, 'interval', seconds=5)
sched.start()

and

from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()

@sched.scheduled_job('interval', id='my_job_id', seconds=5)
def my_interval_job():
    print 'Hello World!'
sched.start()

Either should work according to the docs, but the job never fires...


UPDATE:
It turns out there was something else, environment-related, preventing the task from running. This morning, the task is working fine without any modifications to the code from yesterday.


UPDATE 2:
After further testing, I've found that 'interval' jobs seem to be generally flaky... The above code now works in my dev environment, but not when I deploy to a staging env (I'm using a heroku app for staging). I have other apscheduler 'cron' jobs that work just fine in the staging/production envs.

When I turn on DEBUG logging for the "apscheduler.schedulers" logger, the log indicates that the interval job is added:

Added job "my_cron_job1" to job store "default"
Added job "my_cron_job2" to job store "default"
Added job "my_interval_job" to job store "default"
Scheduler started
Adding job tentatively -- it will be properly scheduled when the scheduler starts
Adding job tentatively -- it will be properly scheduled when the scheduler starts
Looking for jobs to run
Next wakeup is due at 2015-03-24 15:05:00-07:00 (in 254.210542 seconds)

How can the next wakeup be due 254 seconds from now when the interval job is set to 5 seconds??

like image 994
Troy Avatar asked Mar 24 '15 01:03

Troy


People also ask

How do I use AP scheduler?

APScheduler has three built-in triggers: date : Use when you want to run the job just once at a certain point of time. interval : Use when you want to run the job at fixed intervals of time. cron : Use when you want to run the job periodically at certain time(s) of day.

What is background scheduler?

BackgroundScheduler is a scheduler provided by APScheduler that runs in the background as a separate thread. Below is an example of a background scheduler. import time from datetime import datetime from apscheduler.

What is Max_instances in APScheduler?

The max_instances only tells you how many concurrent jobs you can have. APScheduler has three types of triggers: date interval cron. interval and cron repeat forever, date is a one-shot on a given date.

What is APScheduler Python?

Advanced Python Scheduler (APScheduler) is a Python library that lets you schedule your Python code to be executed later, either just once or periodically. You can add new jobs or remove old ones on the fly as you please.


3 Answers

You need to keep the thread alive. Here is a example of how I used it.

from subprocess import call

import time
import os
from pytz import utc

from apscheduler.schedulers.background import BackgroundScheduler


def job():
    print("In job")
    call(['python', 'scheduler/main.py'])


if __name__ == '__main__':
    scheduler = BackgroundScheduler()
    scheduler.configure(timezone=utc)
    scheduler.add_job(job, 'interval', seconds=10)
    scheduler.start()
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))

    try:
        # This is here to simulate application activity (which keeps the main thread alive).
        while True:
            time.sleep(5)
    except (KeyboardInterrupt, SystemExit):
        # Not strictly necessary if daemonic mode is enabled but should be done if possible
        scheduler.shutdown()
like image 194
Riaan Steyn Avatar answered Sep 24 '22 03:09

Riaan Steyn


I haven't figured out what caused the original issue, but I got around it by swapping the order in which the jobs are scheduled, so that the 'interval' job is scheduled BEFORE the 'cron' jobs.

i.e. I switched from this:

def my_cron_job1():
    print "cron job 1"

def my_cron_job2():
    print "cron job 2"

def my_interval_job():
    print "interval job"

if __name__ == '__main__':
    from apscheduler.schedulers.blocking import BlockingScheduler
    sched = BlockingScheduler(timezone='MST')

    sched.add_job(my_cron_job1, 'cron', id='my_cron_job1', minute=10)
    sched.add_job(my_cron_job2, 'cron', id='my_cron_job2', minute=20)

    sched.add_job(my_interval_job, 'interval', id='my_job_id', seconds=5)

to this:

def my_cron_job1():
    print "cron job 1"

def my_cron_job2():
    print "cron job 2"

def my_interval_job():
    print "interval job"

if __name__ == '__main__':
    from apscheduler.schedulers.blocking import BlockingScheduler
    sched = BlockingScheduler(timezone='MST')

    sched.add_job(my_interval_job, 'interval', id='my_job_id', seconds=5)

    sched.add_job(my_cron_job1, 'cron', id='my_cron_job1', minute=10)
    sched.add_job(my_cron_job2, 'cron', id='my_cron_job2', minute=20)

and now both the cron jobs and the interval jobs run without a problem in both environments.

like image 39
Troy Avatar answered Sep 23 '22 03:09

Troy


How can the next wakeup be due 254 seconds from now when the interval job is set to 5 seconds??

It's simple: you have many pending executions as your most of the jobs didn't completed in the interval-window of time.

You could use the following parameters in order to sort this out:

 **misfire_grace_time**:    Maximum time in seconds for the job execution to be allowed to delay before it is considered a misfire 
 **coalesce**:  Roll several pending executions of jobs into one

To read more, check the documentation here.

like image 30
Amirkhm Avatar answered Sep 23 '22 03:09

Amirkhm