Flask中有没有办法将响应发送给客户端,然后继续进行一些处理?我有几个要完成的簿记任务,但我不想让客户等待.
请注意,这些实际上是我想要做的很快的事情,因此创建新线程或使用队列在这里并不合适.(这些快速的事情之一实际上是在作业队列中添加了一些东西.)
可悲的是,在响应返回给客户端后,拆卸回调不会执行:
import flask
import time
app = flask.Flask("after_response")
@app.teardown_request
def teardown(request):
time.sleep(2)
print("teardown_request")
@app.route("/")
def home():
return "Success!\n"
if __name__ == "__main__":
app.run()
Run Code Online (Sandbox Code Playgroud)
卷曲时,您会注意到在响应显示之前有 2 秒的延迟,而不是卷曲立即结束,然后在 2 秒后记录。日志进一步证实了这一点:
teardown_request
127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 -
Run Code Online (Sandbox Code Playgroud)
返回响应后执行的正确方法是使用 WSGI 中间件,它为响应迭代器的close 方法添加一个钩子。这不像teardown_request装饰器那么简单,但它仍然非常简单:
import traceback
from werkzeug.wsgi import ClosingIterator
class AfterResponse:
def __init__(self, app=None):
self.callbacks = []
if app:
self.init_app(app)
def __call__(self, callback):
self.callbacks.append(callback)
return callback
def init_app(self, app):
# install extension
app.after_response = self
# install middleware
app.wsgi_app = AfterResponseMiddleware(app.wsgi_app, self)
def flush(self):
for fn in self.callbacks:
try:
fn()
except Exception:
traceback.print_exc()
class AfterResponseMiddleware:
def __init__(self, application, after_response_ext):
self.application = application
self.after_response_ext = after_response_ext
def __call__(self, environ, start_response):
iterator = self.application(environ, start_response)
try:
return ClosingIterator(iterator, [self.after_response_ext.flush])
except Exception:
traceback.print_exc()
return iterator
Run Code Online (Sandbox Code Playgroud)
然后您可以像这样使用它:
@app.after_response
def after():
time.sleep(2)
print("after_response")
Run Code Online (Sandbox Code Playgroud)
从 shell 中,您将看到响应立即返回,然后在 2 秒after_response后将命中日志:
127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 -
after_response
Run Code Online (Sandbox Code Playgroud)
这是此处提供的先前答案的摘要。
快速和简单的方法。
我们将使用 pythons线程库来实现这一点。
您的 API 使用者已发送要处理的内容,该内容由需要10 秒执行时间的my_task()函数处理。但是 API 的使用者希望在他们访问您的 API 后立即得到响应,即return_status()函数。
你扎的my_task一个线程,然后返回到API消费的快速反应,而背景中的大进程得到compelete。
下面是一个简单的 POC。
import os
from flask import Flask,jsonify
import time
from threading import Thread
app = Flask(__name__)
@app.route("/")
def main():
return "Welcome!"
@app.route('/add_')
def return_status():
"""Return first the response and tie the my_task to a thread"""
Thread(target = my_task).start()
return jsonify('Response asynchronosly')
def my_task():
"""Big function doing some job here I just put pandas dataframe to csv conversion"""
time.sleep(10)
import pandas as pd
pd.DataFrame(['sameple data']).to_csv('./success.csv')
return print('large function completed')
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
Run Code Online (Sandbox Code Playgroud)
我的博客也有类似的问题。我想在发布新评论时向订阅评论的人发送通知电子邮件,但我不想让发布评论的人在收到回复之前等待所有电子邮件发送。
我multiprocessing.Pool为此使用了一个。我启动了一个由一名工作人员组成的池(这已经足够了,低流量站点),然后每次我需要发送电子邮件时,我都会在 Flask 视图函数中准备所有内容,但send_email通过apply_async.
| 归档时间: |
|
| 查看次数: |
11547 次 |
| 最近记录: |