2017-09-12 12 views
-1

現在、ソケットとセロリを使用してリアルタイムチャートを作成できるフラスコアプリケーションを設計しようとしています。データを非同期的に取得し、それをソケット経由でクライアントに送信したいと考えています。私はしかし、エラーを取得しています:RuntimeError: Working outside of request context.私はソケットが最初に接続するときこれを取得します。Flask + Celery + socketio 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 

チャートジャバスクリプト

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) 
}); 
+1

エラーが発生した瞬間はありますか?質問に完全な痕跡を追加できますか?あなたは 'Flask'アプリケーションと' Celery'アプリケーションをどのように実行しますか? –

+0

私は 'python main.py'を使ってCeleryアプリケーションを実行します – Warmley

+0

' send() 'はsocketio装飾関数' handle_connection'の中になければならないと思います。 'async_data'タスクのコールバックで' send'を使ってみることができます。 http://docs.celeryproject.org/en/latest/userguide/calling.html#linking-callbacks-errbacks –

答えて

1

理由はフラスコのみです。

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) 

実行セロリ、フラスコのアプリケーション、オープン '/' ルート:ちょっとしたテスト(main.py)を作ってみましょう。次のエラーが表示されます:

RuntimeError: Working outside of request context

どのように動作するのですか?あなたはjsonifyメソッドを使用しています。ドキュメントでわかるように、JSON出力をapplication/json mimetypeのResponseオブジェクトに変換します。しかしCelery taskは、Flaskの現在の/アクティブな応答について何も知らない。これはちょうど非同期のコード/処理です。 jsonでセロリで作業する必要がある場合は、任意のlib(json、ujson、simplejsonなど)を使用できます。

jsonifyjson.dumps({"result": sample(range(101), 6)})に変更します。すべてがうまく動作することがわかります。

これが役に立ちます。

+0

これはちょっと役立ちます。この問題はsocketioを使用しているときに発生します。 'async_data()'の結果をクライアント – Warmley

+1

@Warmleyに送信したい場合、問題はsocketio、jsなどではありません。 'Celery task'から結果を取得する必要がある場合は、[AsyncResult](http://docs.celeryproject.org/ja/latest/reference/celery.result.html#celery.result.AsyncResult)を使用してください。タスクが開始されたとき、およびクライアント側からのチェックステータスの後に、タスクのUUIDを取得できます。 –

+0

しかし、私のクライアント側はポーリングされませんか? websocketのポイントが長く投票するのではないのですか? – Warmley

関連する問題