jds
jds

Reputation: 8259

Save to database outside of Flask-SQLAlchemy session

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

Answers (1)

zvone
zvone

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

Related Questions