BackgroundScheduler.get_jobs() hangs when used with Flask and Sqlalchemy
See original GitHub issueMotivation
On startup, I’d like to be able to add a persistent job store and add a job only if that job store is empty.
What works
With sqlalchemy, but without flask, the following code works:
from time import sleep
import sqlalchemy as sa
# Connect to example.sqlite and add a new job only if there are no jobs already.
from apscheduler.schedulers.background import BackgroundScheduler
log = print
engine = sa.create_engine('sqlite:///{}'.format('example.sqlite'))
def alarm():
print('Alarm')
if __name__ == '__main__':
scheduler = BackgroundScheduler()
log("created scheduler")
scheduler.add_jobstore('sqlalchemy', engine=engine)
log("Added jobstore")
scheduler.start()
log("Started scheduler")
if not scheduler.get_jobs():
log("Added job")
scheduler.add_job(alarm, 'interval', seconds=20)
else:
log("Didn't add job.")
try:
while True:
sleep(2)
except (KeyboardInterrupt, SystemExit):
pass
With Flask but without sqlalchemy, the following works. It doesn’t make use of persistent storage, of course, but get_jobs() will return []
.:
import os
from time import sleep
import flask
from apscheduler.schedulers.background import BackgroundScheduler
# Verify that apscheduler works with flask, as long as we don't use
# persistent storage.
# run with
# & { $env:FLASK_APP='demo.py'; $env:FLASK_DEBUG=1; python -m flask
run}
app = flask.Flask(__name__)
log = app.logger.info
log("Created App")
def alarm():
print('Alarm')
if not app.debug or os.environ.get("WERKZEUG_RUN_MAIN") == 'true':
scheduler = BackgroundScheduler()
log("created scheduler")
scheduler.start()
log("Started scheduler")
if not scheduler.get_jobs():
app.logger.info("Added job")
scheduler.add_job(alarm, 'interval', seconds=20)
else:
app.logger.info("Didn't add job.")
What doesn’t work:
When I try to add a persistent job store to this flask app, scheduler.get_jobs()
hangs:
import os
from time import sleep
import sqlalchemy as sa
import flask
from apscheduler.schedulers.background import BackgroundScheduler
# Hangs at get_jobs()
app = flask.Flask(__name__)
log = app.logger.info
log("Created App")
### NEW ###
engine = sa.create_engine('sqlite:///{}'.format('example.sqlite'))
###########
def alarm():
print('Alarm')
# Don't create two schedulers when running in debug mode.
if not app.debug or os.environ.get("WERKZEUG_RUN_MAIN") == 'true':
scheduler = BackgroundScheduler()
log("created scheduler")
### NEW ###
scheduler.add_jobstore('sqlalchemy', engine=engine)
log("Added jobstore")
###########
scheduler.start()
log("Started scheduler")
if not scheduler.get_jobs():
app.logger.info("Added job")
scheduler.add_job(alarm, 'interval', seconds=20)
else:
app.logger.info("Didn't add job.")
Environment
Windows 10 Python 3.5.3
Running in a virtual environment with:
Package Version
------------ -------
APScheduler 3.4.0
click 6.7
Flask 0.12.2
itsdangerous 0.24
Jinja2 2.10
MarkupSafe 1.0
pip 9.0.1
pytz 2017.3
setuptools 37.0.0
six 1.11.0
SQLAlchemy 1.1.15
tzlocal 1.4
Werkzeug 0.12.2
wheel 0.30.0
Edit:
This also appears on Linux with 3.6.2. All the package versions are the same.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:1
- Comments:23 (9 by maintainers)
Top Results From Across the Web
User guide — APScheduler 3.9.1 documentation
BackgroundScheduler : use when you're not using any of the frameworks below, and want the scheduler to run in the background inside your...
Read more >Python Apscheduler Jobstore Database Jobs getting stored ...
We are using Mysql to store scheduler jobs using JobStores in Apscheduler ... BackgroundScheduler(jobstores=jobstores, executors=executors, ...
Read more >Flask-SQLAlchemy — Flask-SQLAlchemy Documentation (3.0.x)
It simplifies using SQLAlchemy with Flask by setting up common objects and patterns for using those objects, such as a session tied to...
Read more >Python Flask Tutorial #4: Using SQLAlchemy to create models
In this #4 video of my Flask Tutorial for absolute beginners we'll use SQLAlchemy ORM to create and store Posts.In this video:- how...
Read more >Python Flask Tutorial #5: SQLAlchemy ManyToMany ...
Python Flask Tutorial #5: SQLAlchemy ManyToMany relationship | Flask crash course for beginners.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks for responding @agronholm. I dropped flask-apscheduler and am now using APScheduler directly. I am able to replicate the issue. I’ve done some debugging and have found a deadlock caused in relation to
_jobstores_lock
.After starting APScheduler a thread is spun off which executes
_process_jobs
, this sets the_jobstores_lock
here: https://github.com/agronholm/apscheduler/blob/cbf2eeb21695343c1996e59732adbc8fbbab6842/apscheduler/schedulers/base.py#L929A query executed within the context of this lock by a function called
get_due_jobs
never returns. I followed the execution down to the last executed line and it seems there is an issue receiving a new cursor from SQLAlchemy’s connection pool (https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/pool.py#L970).Simultaneously, while the ^^^ request hangs, the main thread executes
add_job
which also requests a lock from_jobstores_lock
. That lock request occurs here: https://github.com/agronholm/apscheduler/blob/cbf2eeb21695343c1996e59732adbc8fbbab6842/apscheduler/schedulers/base.py#L428My config
init.py
config/default.py
Output
Yes this is still relevant. I ran into this issue a few days ago using gunicorn, flask, apscheduler and sqlalchemy.