我有2个功能。
第一个函数将接收到的数据存储在一个列表中,第二个函数将数据写入一个csv文件中。
我正在使用Flask。每当调用Web服务时,它将存储数据并发送对它的响应,一旦发送响应,它将触发第二个功能。
我的代码:
from flask import Flask, flash, request, redirect, url_for, session
import json
app = Flask(__name__)
arr = []
@app.route("/test", methods=['GET','POST'])
def check():
arr.append(request.form['a'])
arr.append(request.form['b'])
res = {'Status': True}
return json.dumps(res)
def trigger():
df = pd.DataFrame({'x': arr})
df.to_csv("docs/xyz.csv", index=False)
return
显然第二个函数没有被调用。
有没有办法做到这一点?
P.S:我的现实生活的问题有所不同,其中trigger
函数很耗时,我不希望用户等待它完成执行。
答案 0 :(得分:1)
我实际上正在处理我这边的另一个有趣的案例,在该案例中,我将工作传递给了一个python worker,该python worker将工作发送到redis队列。有一些很棒的博客在Flask上使用redis,您基本上需要确保redis正在运行(能够在端口6379上连接)
工人看起来像这样:
import os
import redis
from rq import Worker, Queue, Connection
listen = ['default']
redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379')
conn = redis.from_url(redis_url)
if __name__ == '__main__':
with Connection(conn):
worker = Worker(list(map(Queue, listen)))
worker.work()
在我的示例中,我有一个查询数据库使用情况的函数,由于它可能是一个漫长的过程,因此我将其传递给工作程序(作为单独的脚本运行)
def post(self):
data = Task.parser.parse_args()
job = q.enqueue_call(
func=migrate_usage, args=(my_args),
result_ttl=5000
)
print("Job ID is: {}".format(job.get_id()))
job_key = job.get_id()
print(str(Job.fetch(job_key, connection=conn).result))
if job:
return {"message": "Job : {} added to queue".format(job_key)}, 201
归功于以下文章:
https://realpython.com/flask-by-example-implementing-a-redis-task-queue/#install-requirements
答案 1 :(得分:1)
一种解决方案是让后台线程监视队列。您将csv数据放入队列中,后台线程将使用它。您可以在第一个请求之前启动这样的线程:
import threading
from multiprocessing import Queue
class CSVWriterThread(threading.Thread):
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.input_queue = Queue()
def send(self, item):
self.input_queue.put(item)
def close(self):
self.input_queue.put(None)
self.input_queue.join()
def run(self):
while True:
csv_array = self.input_queue.get()
if csv_array is None:
break
# Do something here ...
df = pd.DataFrame({'x': csv_array})
df.to_csv("docs/xyz.csv", index=False)
self.input_queue.task_done()
time.sleep(1)
# Done
self.input_queue.task_done()
return
@app.before_first_request
def activate_job_monitor():
thread = CSVWriterThread()
app.csvwriter = thread
thread.start()
然后在返回的代码中将消息放入队列中
@app.route("/test", methods=['GET','POST'])
def check():
arr.append(request.form['a'])
arr.append(request.form['b'])
res = {'Status': True}
app.csvwriter.send(arr)
return json.dumps(res)
答案 2 :(得分:1)
P.S:我的现实生活的问题有所不同,其中触发功能很耗时,我不希望用户等待它完成执行。
考虑使用celery来解决您要解决的问题。来自文档:
Celery是一个简单,灵活且可靠的分布式系统,可以处理大量消息,同时为操作提供维护该系统所需的工具。
我建议您按照here的说明将芹菜与烧瓶应用程序集成。这样,您的trigger
方法将成为一项简单的芹菜任务,您可以执行它而不必担心响应时间长。
答案 3 :(得分:0)
您可以尝试使用流式传输。请参见下一个示例:
import time
from flask import Flask, Response
app = Flask(__name__)
@app.route('/')
def main():
return '''<div>start</div>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', '/test', true);
xhr.onreadystatechange = function(e) {
var div = document.createElement('div');
div.innerHTML = '' + this.readyState + ':' + this.responseText;
document.body.appendChild(div);
};
xhr.send();
</script>
'''
@app.route('/test')
def test():
def generate():
app.logger.info('request started')
for i in range(5):
time.sleep(1)
yield str(i)
app.logger.info('request finished')
yield ''
return Response(generate(), mimetype='text/plain')
if __name__ == '__main__':
app.run('0.0.0.0', 8080, True)
此示例中的所有魔术都是使用genarator进行的,您可以在其中执行一些工作并生成空数据以结束流后开始响应数据。
答案 4 :(得分:0)
您可以通过结合 after_this_request 和 response.call_on_close 来推迟具有有限上下文的路由特定操作。请注意,请求和响应上下文将不可用,但路由函数上下文仍然可用。因此,您需要将需要的任何请求/响应数据复制到本地变量中以进行延迟访问。
我将您的数组移动到本地 var 以显示函数上下文是如何保留的。您可以将 csv write 函数更改为 append,这样您就不会无休止地将数据推送到内存中。
from flask import Flask, flash, request, redirect, url_for, session
import json
app = Flask(__name__)
@app.route("/test", methods=['GET','POST'])
def check():
arr = []
arr.append(request.form['a'])
arr.append(request.form['b'])
res = {'Status': True}
@flask.after_this_request
def add_close_action(response):
@response.call_on_close
def process_after_request():
df = pd.DataFrame({'x': arr})
df.to_csv("docs/xyz.csv", index=False)
return response
return json.dumps(res)