Reputation: 8259
I have a long-running job to build an analytics report. I'd like to kick off the job, give the user a permanent link, and then allow the user to refresh the page to see if their report is ready. The report has a status that is initialized to pending
. After the job is complete, I need to save the status to ready
.
I kick off this job using Python's threading
module. The problem is that when I save the status, I am no longer in a valid Flask-SQLAlchemy session. Here is the error:
RuntimeError: application not registered on db instance and no application bound to current context
And here is the code:
from threading import Thread
from app import db
from app.models import Report
def build():
report = __save_and_detach_report(Report())
thread = Thread(target=__build, args=(report,))
thread.daemon = True
thread.start()
return report.id
def __build(report):
print('starting job')
time.sleep(10)
print('job complete')
__set_report_ready(report)
def __save_and_detach_report(report):
with session_scope() as session:
session.add(report)
session.commit()
session.expunge(report)
return report
def __set_report_ready(report):
with session_scope() as session:
report.ready()
session.merge(report)
@contextmanager
def session_scope():
try:
yield db.session
db.session.commit()
except Exception as e:
print 'Rolling back database'
print e
db.session.rollback()
The error is thrown on the call to merge
.
Upvotes: 1
Views: 971
Reputation: 19332
You should open a new session when you want to save to database.
I am not sure what your session_scope()
does. I have something like this in one of my projects:
@contextmanager
def db_session():
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
Then, in a thread I can do:
with db_session() as session:
# save to data base
Upvotes: 1