python - RuntimeError:在 Python 中使用 Celery 和 Flask 在应用程序上下文之外工作
问题描述
我已经阅读了许多不同的博客来解释如何结合 Flask 和 Celery。我还阅读了大量关于该主题的堆栈问题。但是,已经好几天了,我仍然无法解决这个“RuntimeError:在应用程序上下文之外工作”,我不知道此时我能做些什么来解决这个问题。
该项目是这样完成的:
/应用
- __ 在里面__
- 楷模
- 路线
- tfidf_matching
- celery_worker
- 配置
- wsgi
我实现了我的项目以拥有本文中所做的工厂架构。然后,如本文所述,已完成 celery 实现以适应该工厂架构。
HTTP 请求在 routes.py 中处理,并将调用 celery 任务在后台完成。同时,应用程序可以继续运行并做其他事情。它将发送一个带有另一个函数的 POST HTTP,当 celery 任务完成后,它将发送一个 celery 结果的 POST HTTP。
routes.py 包含以下内容,我已将其简化为重要部分:
from flask import request, make_response, jsonify, copy_current_request_context
from flask import current_app as app
from application import tfidf_matching
import time
from application.models import db, Status
from app import cel
def snooze(maxTime):
...
@app.before_first_request
def default_values():
...
@cel.task
def tfidf(question):
with app.app_context:
answer = tfidf_matching.getMatchingSentence(question)
...
return answer
@app.route('/webhook', methods=['GET', 'POST'])
def webhook():
req = request.get_json(force=True)
...
if ... :
user_input = req.get('queryResult').get('queryText')
answer = tfidf.apply_async(args=[user_input], expires=60)
...
snooze(4)
response = {'followupEventInput': {'name': 'snooze'}}
if ...:
response = {'fulfillmentText': answer}
return make_response(jsonify(response))
我尝试使用 @copy_current_request_context 和 app.app_context 来解决其他堆栈溢出问题中建议的错误,但没有成功。
使用以下命令启动 Celery:
celery worker -A celery_worker.cel --loglevel=info
celery_worker.py 包含以下内容:
import os
from app.routes import tfidf
from application import cel, create_app
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
app.app_context().push()
我不确定是否有必要,但如果我还要添加 init 和 wsgi 内容。Models 是一个 SQLAlchemy 数据库,这似乎不相关,所以我不会添加这部分。
__ init__.py 包含以下内容:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from celery import Celery
from config import config, Config
db = SQLAlchemy()
cel = Celery(__name__, broker=Config.broker_url, backend=Config.result_backend)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
app.config.update(
broker_url='redis://localhost:6379',
result_backend='redis://localhost:6379',
SQLALCHEMY_DATABASE_URI='postgresql://postgres:APG@localhost:5432/Dialogflow',
SQLALCHEMY_TRACK_MODIFICATIONS='None'
)
cel.conf.update(
result_expires=3600,
)
cel.conf.update(app.config)
with app.app_context():
from . import routes
db.create_all()
return app
wsgi.py 包含以下内容:
import os
from application import create_app
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
if __name__ == "__main__":
app.run(host='0.0.0.0')
最后,这是堆栈跟踪:
Traceback (most recent call last):
File "c:\users\emma\appdata\local\programs\python\python37\lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "c:\users\emma\appdata\local\programs\python\python37\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\Emma\AppData\Local\Programs\Python\Python37\Scripts\celery.exe\__main__.py", line 7, in <module>
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\__main__.py", line 16, in main
_main()
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\celery.py", line 322, in main
cmd.execute_from_commandline(argv)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\celery.py", line 495, in execute_from_commandline
super(CeleryCommand, self).execute_from_commandline(argv)))
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\base.py", line 289, in execute_from_commandline
argv = self.setup_app_from_commandline(argv)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\base.py", line 509, in setup_app_from_commandline
self.app = self.find_app(app)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\base.py", line 531, in find_app
return find_app(app, symbol_by_name=self.symbol_by_name)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\app\utils.py", line 373, in find_app
sym = symbol_by_name(app, imp=imp)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\bin\base.py", line 534, in symbol_by_name
return imports.symbol_by_name(name, imp=imp)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\kombu\utils\imports.py", line 57, in symbol_by_name
module = imp(module_name, package=package, **kwargs)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\celery\utils\imports.py", line 111, in import_from_cwd
return imp(module, package=package)
File "c:\users\emma\appdata\local\programs\python\python37\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "C:\Users\Emma\PycharmProjects\APG_Dialogflow\celery_worker.py", line 2, in <module>
from application.routes import tfidf
File "C:\Users\Emma\PycharmProjects\APG_Dialogflow\application\routes.py", line 21, in <module>
@app.before_first_request
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\werkzeug\local.py", line 348, in __getattr__
return getattr(self._get_current_object(), name)
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\werkzeug\local.py", line 307, in _get_current_object
return self.__local()
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\flask\globals.py", line 52, in _find_app
raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
编辑
通过按照 Miguel 的建议进行更改from flask import current_app as app
,错误消失了。
我将导入更改为from wsgi import app
在 routes.py 中,但这不起作用。我的应用程序实例应该以另一种方式导入,但我不知道如何
使用以下命令运行烧瓶时: flask run 我得到以下 Traceback
Traceback (most recent call last):
File "c:\users\emma\appdata\local\programs\python\python37\lib\site-packages\flask\cli.py", line 240, in locate_app
__import__(module_name)
File "C:\Users\Emma\PycharmProjects\APG_Dialogflow\wsgi.py", line 4, in <module>
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
File "C:\Users\Emma\PycharmProjects\APG_Dialogflow\application\__init__.py", line 28, in create_app
from . import routes
File "C:\Users\Emma\PycharmProjects\APG_Dialogflow\application\routes.py", line 6, in <module>
from wsgi import app
ImportError: cannot import name 'app' from 'wsgi' (C:\Users\Emma\PycharmProjects\APG_Dialogflow\wsgi.py)
解决方案
问题是你的代码中有这个:
from flask import current_app as app
然后你使用app
in@app.route
和@app.before_first_request
。
这是不正确的,Flask 无法弄清楚你的应用程序实例是什么。您需要做的是使用真实的应用程序实例而不是current_app
.
您可以current_app
在视图函数中使用,因为 Flask 为您设置了应用程序上下文,但您不能在应用程序的全局范围内使用它。
更新后更新答案:
你现在怎么一个循环依赖问题。注意最后一个堆栈跟踪是如何显示的wsgi.py
,进入application/__init__.py
,然后到application/routes.py
最后返回到wsgi.py
。
在 Flask 应用程序中解决此问题的一个相当常见的解决方案是将from . import routes
文件application/__init__.py
中的 . 文件的底部。我相信这将消除循环依赖。
推荐阅读
- python - np.random.choice 在矢量化时未返回正确的权重
- android - 在观察到的 livedata 中接收 null 而不是 object
- javascript - 给出原因时错误处理未捕获错误 discord.js 静音
- keycloak - Keycloak:在社交身份提供者登录时传递自定义用户属性
- flutter - 文本与侧面的容器居中对齐
- django - Django 两个模型 CreateView
- c++ - 在 C++11 中不允许使用 auto
- excel - 使用 API 填充 Excel
- python - 如何使用 Mariadb 在 python sqlalchemy 中定义 DateTime?
- json - 将多个 json 对象转换为单个数据帧/csv