javascript - Flask + Celery + socketio 运行时错误 : Working outside of request context

标签 javascript python flask celery

我目前正在尝试设计一个 flask 应用程序,它允许通过使用套接字和 celery 来显示实时图表。我希望能够异步获取数据,然后通过套接字将其发送到客户端。但是,我收到错误:RuntimeError:在请求上下文之外工作。当套接字首次连接时,我收到此错误。

堆栈跟踪

Traceback (most recent call last):
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/celery/app/trace.py", line 374, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/bev/PycharmProjects/flask_project/celery_config.py", line 15, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/celery/app/trace.py", line 629, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/bev/PycharmProjects/flask_project/main.py", line 20, in async_data
    send(jsonify({"result": sample(range(101), 6)}))
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/flask/json.py", line 251, in jsonify
    if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] and not request.is_xhr:
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
    return self.__local()
  File "/Users/bev/.virtualenvs/flask_project/lib/python3.6/site-packages/flask/globals.py", line 37, in _lookup_req_object
    raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

main.py

from flask import Flask, render_template, jsonify
from flask_socketio import SocketIO, send
from random import sample
from celery_config import make_celery


app = Flask(__name__)
app.config["SECRET_KEY"] = "thisisasecret"
socketio = SocketIO(app)

app.config.update(
    CELERY_BROKER_URL="amqp://localhost//",
    CELERY_RESULT_BACKEND="rpc://"
)
celery = make_celery(app)


@celery.task(name="main.async_data")
def async_data():
    # for now this is very small as an example
    # preferably batched to be done every 15 minutes.
    send(jsonify({"result": sample(range(101), 6)}))
    return True


@app.route("/")
def index():
    return render_template("chart.html")


@socketio.on("connect")
def handle_connection():
    async_data.delay()
    print("You are connected and we are getting your data")


if __name__ == "__main__":
    socketio.run(app, debug=True)

celery_config.py

from celery import Celery


def make_celery(app):
    celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
                    broker=app.config['CELERY_BROKER_URL'])
    celery.conf.update(app.config)
    TaskBase = celery.Task

    class ContextTask(TaskBase):
        abstract = True

        def __call__(self, *args, **kwargs):
            with app.app_context():
                return TaskBase.__call__(self, *args, **kwargs)

    celery.Task = ContextTask
    return celery

图表 JavaScript

let chartConfig = {
    type: "line",
    data: {
        labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
        datasets: [{
            label: "GOOG",
            data: [],
            borderColor: "rgba(22, 172, 65, 1)",
            borderWidth: 1,
            fill:false
        }]
    }
};

let socket = io.connect("http://" + document.domain + ':' + location.port);

socket.on("connect", function() {
    socket.send("Connected Socket off to get data");
});

socket.on("message", function (data) {
    chartConfig.data.datasets[0].data = data.result;
    let ctx = document.getElementById("myChart").getContext("2d");
    let myLineChart = new Chart(ctx, chartConfig)
});

最佳答案

原因只在 Flask 中。让我们做一个小测试(main.py):

from random import sample
from flask import Flask, jsonify
from celery_config import make_celery

app = Flask(__name__)
app.config["SECRET_KEY"] = "thisisasecret"

app.config.update(
    CELERY_BROKER_URL="redis://localhost:6379/0", # or your broker
    CELERY_RESULT_BACKEND="redis://localhost:6379/0" # or your broker
)
celery = make_celery(app)

@celery.task(name="main.async_data")
def async_data():
    jsonify({"result": sample(range(101), 6)})
    return True

@app.route("/")
def index():
    async_data.delay()
    return 'test'

if __name__ == "__main__":
    app.run(debug=True)

运行 Celery 和 Flask 应用程序,打开“/”路线。您将看到下一个错误:

RuntimeError: Working outside of request context

它是如何工作的。您使用 jsonify方法。正如您在文档中看到的,它将 JSON 输出转换为具有 application/json mimetype 的 Response 对象。但是 Celery 任务不知道 Flask 的当前/事件响应的任何信息。这只是异步代码/处理。如果您需要在 celery 中使用 json,您可以使用任何 lib(json、ujson、simplejson 等)。

现在让我们将 jsonify 更改为 json.dumps({"result": Sample(range(101), 6)})。您会发现一切正常。

希望这有帮助。

关于javascript - Flask + Celery + socketio 运行时错误 : Working outside of request context,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46186336/

相关文章:

python - MySQLdb 和 Scrapy : INSERT INTO Error

python - 如何从我的电脑创建可供内联网上任何其他电脑访问的服务器

Python-Flask-Redis-ResponseError : unknown command 'SETEX'

javascript - 为 IE6 调试 javascript

javascript - 使用 pako.js 未捕获不正确的 header 检查

javascript - 获取纸张对话框内 polymer 纸张输入的输入值

python - Flask-Restful 优于 Flask-ReSTLess

javascript - 如何为移动体验制作响应式图片

python - 线性方程的系数错误

python - 值错误: The number of observations cannot be determined on an empty distance matrix