apscheduler in Flask executes twice [duplicate]
Asked Answered
M

5

61

I have problem when i am using apscheduler in my flask application.

In my view.py file i am writing like this

import time
from apscheduler.scheduler import Scheduler

def test_scheduler():
     print "TEST"
     print time.time()


sched = Scheduler()
sched.add_interval_job(test_scheduler, seconds=5)
sched.start()

And then this method test_scheduler() executes twice in every five second

TEST 1360844314.01 TEST 1360844314.2

Murrhine answered 14/2, 2013 at 12:22 Comment(2)
Please have a look here, had the same issue in Django. https://mcmap.net/q/152355/-make-sure-only-one-worker-launches-the-apscheduler-event-in-a-pyramid-web-app-running-multiple-workersAllotrope
This is absolutely crazy. I am debugging some problems for two weeks and only few minutes ago I realised it was scheduler running twice! And Google directed me immediately here.Underproof
M
-3

I've made it, I added in add_interval_job parameter to start after a certain time point

sched.add_interval_job(test_scheduler, seconds=5, start_date='2013-02-13 00:00')
Murrhine answered 14/2, 2013 at 13:16 Comment(1)
Maybe this solves your problem but your question is completely unrelated to this answerReflux
E
86

In debug mode, Flask's reloader will load the flask app twice (How to stop Flask from initialising twice in Debug Mode?). I'm not sure why this is, but it causes apscheduler's jobs to be scheduled twice. A quick print "loaded scheduler" right before sched.start() confirms this.

There are a couple ways around this, as mentioned in the linked answer. The one I found that worked best is just to disable the reloader like so:

app.run(use_reloader=False)

It means I have to reload my app manually as I develop it, but it's a small price to pay to get apscheduler working.

Exaggerative answered 19/3, 2013 at 4:38 Comment(4)
Excellent, just the answer I needed inbound from Google. OP should accept.Barr
This answer worked for me too and is the right answer factually. Could you please accept this?Hedgehog
is there no way to catch the restart signal/event. Its very bad to lose this feature only for using a scheduling lib.Pratt
https://mcmap.net/q/152095/-apscheduler-in-flask-executes-twice-duplicate is better, no need to compromise on reloading.Publicize
C
57

When using the reloader, there are the master and child processes. Your scheduler thread runs in both. You need to prevent the scheduler from running in the master process

if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
  sched = Scheduler()
  sched.add_interval_job(test_scheduler, seconds=5)
  sched.start()
Chockfull answered 27/8, 2014 at 5:29 Comment(8)
Yes, this helps. I tried out a lot of options, including flocked file without succeeding.Sonny
This does not work for me, because app.debug returns False even when Flask is in debug mode, i.e. app.run(host='0.'0.0.0', port=80, debug=True)Underproof
It seems that the problem is that app.run should be the last command, and before you run app.run you cannot know the state of Flask.Underproof
How would this work in django?Calm
@Underproof have a config variable MY_DEBUG=True somewhere and use it in both places i.e. app.run(debug=MY_DEBUG) and if not MY_DEBUG or ... Also there's this commentPublicize
You can set DEBUG = True as a Config object. In this case the app object knows the status before app.run() Worked for me like a charm.Mold
Can totally agree with @MichaelLossagk . So far no complications for me at allMattison
make sure that you run the flask app in debug mode. You can temporarily enable this by running this command export FLASK_DEBUG=1. This is applicable for your current terminal only.Mattison
I
19

You can start the scheduler in Flask's before_first_request() decorator, which "registers a function to be run before the first request to this instance of the application".

import time
import atexit

from apscheduler.schedulers.background import BackgroundScheduler


def print_date_time():
    print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))


@app.before_first_request
def init_scheduler():
    scheduler = BackgroundScheduler()
    scheduler.add_job(func=print_date_time, trigger="interval", seconds=3)
    scheduler.start()
    # Shut down the scheduler when exiting the app
    atexit.register(lambda: scheduler.shutdown())

Note that before_first_request() will always be called again with the first request after server reload.

Imamate answered 21/7, 2016 at 10:11 Comment(3)
You can use this solution along with networklore.com/start-task-with-flask to have the before_first_requested triggered with starting the serverMemberg
This is the best answerDann
Unfortunately the decorator before_first_request has been deprecated :(Austronesia
M
-2

the best solution is to use add_cron_job('*') instead of add_interval_job('*')

Murrhine answered 14/2, 2013 at 13:37 Comment(0)
M
-3

I've made it, I added in add_interval_job parameter to start after a certain time point

sched.add_interval_job(test_scheduler, seconds=5, start_date='2013-02-13 00:00')
Murrhine answered 14/2, 2013 at 13:16 Comment(1)
Maybe this solves your problem but your question is completely unrelated to this answerReflux

© 2022 - 2025 — McMap. All rights reserved.