Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running job causes detachedinstanceerror #221

Open
bnewman70 opened this issue Mar 18, 2023 · 3 comments
Open

Running job causes detachedinstanceerror #221

bnewman70 opened this issue Mar 18, 2023 · 3 comments
Labels

Comments

@bnewman70
Copy link

bnewman70 commented Mar 18, 2023

Is there any chance that when running a job using the scheduler within an app context that it can cause a previous session to detach?

i am using version 1.12.3 of flask-apscheduler, I only get the following error when running a job that uses the database. If I run a job that just prints to screen, I do not get this error.

sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Users at 0x2792f1448b0> is not bound to a Session; lazy load operation of attribute 'profile' cannot proceed.

The call for profile is used by flask-login on @login_required decorator. I have tried many scenarios and this only seems to happen when a job runs. I am using the @scheduler.task decorator to start the job and have my code within this block

with scheduler.app.app_context():

So this works fine
@scheduler.task("interval",id=ups_tracking,seconds=60,max_instances=1,start_date="2000-01-01 12:19:00")
def hello_world():
print("hello world job")

this produces error
@scheduler.task("interval",id=ups_tracking,seconds=60,max_instances=1,start_date="2000-01-01 12:19:00")
def hello_world():
with scheduler.app.app_context():
print("hello world job")

not even doing any db queries
and this only happens when using scheduler.run_job() method on demand.

@christopherpickering
Copy link
Collaborator

hey @bnewman70, so if I understand you correctly, the error is only coming up in jobs that have the @login_required decorator on them as well? Can you share code where the decorator is added?

@bnewman70
Copy link
Author

the jobs don't have the @login_required decorator, the routes do.
Using Flask-login 0.5.0
When I try to access an object under the current__user that's when the error occurs, but only after I call scheduler.run_job and the job runs within the block
with scheduler.app.app_context():

If I do a run_job in a test job that does not run within a with scheduler.app.app_context(): block, the object under my current_user is correctly pulled from the database with no error.

Heres some code blocks in order of execution:

  1. Route for a page that lists all jobs and allows user to perform actions, like pause, resume and run now. Note i added a current_user.profile call as a work around to avoiding the error
    @blueprint.route('/jobs', methods=['GET','POST'])
    @login_required
    def jobs():
    action = request.args.get('action')
    jobs = scheduler.get_jobs()
    print('got jobs',len(jobs))
    if action == 'pause':
    print('pausing job')
    scheduler.pause_job(request.args.get('jid'))
    flash('Job paused',category='success')
    elif action == 'resume':
    scheduler.resume_job(request.args.get('jid'))
    flash('Job Resumed',category='success')
    elif action == 'run_now':
    # avoid detached profile only in run now, pull profile before job runs
    print(current_user.profile)
    scheduler.run_job(request.args.get('jid'))
    flash('Job Started',category='success')

  2. example job, triggering the detached instance error. If I remove with scheduer.app.app_context(), the error does not occur
    @scheduler.task("interval",id=hello_world,seconds=60,max_instances=1,start_date="2000-01-01 12:19:00")
    def hello_world():
    with scheduler.app.app_context():
    print("hello world job")

  3. In my template I show the user profile image from the current_user.profile in the header of each page.. this triggers the error. I an guessing I only see it on run_now because this page immediately reloads after run. Other pages may not be refreshed during a job run.
    {% if current_user.profile %}
    {% for user in current_user.profile %}
    User-Profile-Image
    {% endfor %}
    {% endif %}
    Thanks

@christopherpickering
Copy link
Collaborator

It is difficult to follow, maybe if you have code on github somewhere it would be easier.

It sounds as though you have a db session, and after you pass it into a job, the session is no longer accessible outside the job.

Are you using the extensions pattern (similar to this example) to create you db?

You could have something like

from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy_caching import CachingQuery

db = SQLAlchemy(query_class=CachingQuery)

in your extensions.py and then import it where you need db connections, and use it inside the app_context().

In your init.py you would still need to also import db and initialize it with db.init_app(app)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants