1

I want to schedule and run jobs using APScheduler and the cron format.

from apscheduler.schedulers.background import BackgroundScheduler

def test_func():
    print("Test job func")

scheduler = BackgroundScheduler()

today_str = datetime.today().strftime('%Y-%m-%d')
today_with_time = datetime.strptime(today_str + " " + "12:07:00", "%Y-%m-%d %H:%M:%S")

scheduler.add_job(
                test_func,
                "cron",
                id="test",
                name="test",
                day_of_week="2",
                hour=today_with_time.hour,
                minute=today_with_time.minute,
                replace_existing=False)

Let's say I do this twice, with two different job IDs. There are two jobs, set to run at the exact same time. With one job, it runs once as expected. With two jobs, it runs 4 times. The same happens with other triggers such as DateTrigger.

Note that this is set-up within a Flask app. Normally, the app makes a call to another API to fetch jobs, then schedules them one by one.

EDIT: my actual app fetches 3 jobs and schedules them, all at the same time. When I fetch 1 job instead of 3, the bug does not occur. When I have 3 jobs, the function is run 9 times. With 1 job, it is run once.

Konrad
  • 852
  • 11
  • 31

3 Answers3

0

It's because Flask initialize twice on debug mode.

Short answers: app.run(debug=True, use_reloader=False)

Full answers here: How to stop Flask from initialising twice in Debug Mode?

Yassine Faris
  • 951
  • 6
  • 26
  • Yassine, thank you but I don't believe that is the issue. I came into this problem previously and have set debug=False, use_reloader=False. Additionally, when using DateTrigger the job only runs once as expected. – Konrad Apr 18 '18 at 10:22
0

It turns out I was a genius and initialized a scheduler every time a job was fetched. :-]

So now, I changed the class that manages scheduling (and initializes the scheduler) to a singleton and it works as expected.

Konrad
  • 852
  • 11
  • 31
0

I have gotten the similar issue, as in my case I was initializing the scheduler whenever I am adding new job to it.

solution:

create separate function or class, which initialize/call only once and use the scheduler object wherever you are using job operations eg: add, pause, resume etc

code snippet:

def initialize_scheduler():

    sched = BackgroundScheduler(daemon=False)
    job_store = MongoDBJobStore(database=db.name,
                                collection='scheduler', client=client,
                                pickle_protocol=4)
    sched.add_jobstore(jobstore=job_store, alias='mongodb')
    sched.start()

    return sched

the above sched var will be used every where.

Saurabh
  • 26
  • 4