flask 0.10 mongo working outside of application co

2020-06-24 06:17发布

问题:

i know there are few question on how to deal with flask "working outside of application context", but i could not get them to work for me

I have a long running mongo aggregation queries and are scheduled to run at regular intervals using apscheduler. Below is my app structure, but the tasks fail with "RuntimeError: working outside of application context". ihttp://flask.pocoo.org/docs/patterns/sqlite3/ has some example on using the new flask.g but wondering if anyone can advise on how to properly save mongodb connection globally and share that connection in apscheduler

__init.py__

from app import create_app

app.py

from flask import Flask, request, render_template,g
from .extention import mongo, redis, sched

def create_app(config=None):
"""Create a Flask app."""

    app = Flask(__name__)
    configure_extensions(app)
    return app

def configure_extensions(app):
    mongo.init_app(app) # initialise mongo connection from the config
    redis.init_app(app)

from schedule_tasks import *

extention.py

from flask.ext.pymongo import PyMongo
mongo = PyMongo()

from apscheduler.scheduler import Scheduler
config = {'apscheduler.jobstores.file.class': 'apscheduler.jobstores.shelve_store:ShelveJobStore',
          'apscheduler.jobstores.file.path': '/tmp/sched_dbfile'}
sched = Scheduler(config)

from flask.ext.redis import Redis
redis = Redis()

schedule_tasks.py

from .extention import mongo
@sched.interval_schedule(minutes=1)
def long_running_queries():
    ## mongo agg query ##
    mongo.db.command("aggregate", "collection", pipeline = "some query" )
sched.start()
sched.print_jobs()

回答1:

To understand this error, you need to understand the application context.

It's entirely possible for someone to write multiple Flask applications that all handle their requests in the same process. The docs give the following example...

from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend

application = DispatcherMiddleware(frontend, {
    '/backend':     backend
})

Keep in mind that in this case, the frontend app could use different Mongo setups, but use the exact same Mongo extension object. For this reason, Flask cannot assume which is the "current" app when you run a script. Therefore, things such as url_for(), or many of the methods on extensions like the MongoDB extension, need to know which application is the "current" one before they do anything.

Therefore, whenever you are attempting to use Flask or extension functions to do anything other than set up the applications themselves (with configuration values, etc.), you need to explicitly tell Flask what is the current app to assign to the application context.

The docs give a way that you can do this..

# Be careful about recursive imports here
from . import app
from .extention import mongo

@sched.interval_schedule(minutes=1)
def long_running_queries():
    with app.app_context():
        mongo.db.command("aggregate", "collection", pipeline = "some query" )

So, you'll need to create the app object itself, then use the with app.app_context() line. Within that with statement, all of your calls (such as as those to your Mongo extension) should work. Note that you don't need to do any of this in a view because Flask will automatically do all of this as part of it's handling of a request.