Python 从Flask返回HTTP状态代码,但不返回 上下文 我有一个名为server.py的服务器,它充当GitLab的提交后webhook。 在server.py中,有一个长时间运行的进程约40秒 SSCCE 问题陈述
GitLab的Webhook希望返回代码能够快速返回。因为我的webhook在40秒后或大约40秒后返回;GitLab会发送一次重试,在循环中发送我的长时间运行的进程,直到GitLab尝试了太多次 问题 我是否能够将状态代码从Flask返回到GitLab,但仍然运行长时间运行的流程 我尝试添加一些类似的内容:Python 从Flask返回HTTP状态代码,但不返回 上下文 我有一个名为server.py的服务器,它充当GitLab的提交后webhook。 在server.py中,有一个长时间运行的进程约40秒 SSCCE 问题陈述,python,flask,gitlab,Python,Flask,Gitlab,GitLab的Webhook希望返回代码能够快速返回。因为我的webhook在40秒后或大约40秒后返回;GitLab会发送一次重试,在循环中发送我的长时间运行的进程,直到GitLab尝试了太多次 问题 我是否能够将状态代码从Flask返回到GitLab,但仍然运行长时间运行的流程 我尝试添加一些类似的内容: ... def compile_metadata(): abort(200) # the long running process time.sleep(40)
...
def compile_metadata():
abort(200)
# the long running process
time.sleep(40)
但abort仅支持故障代码
我也尝试过在这个请求之后使用@after\u:
通常,flask只从python的return语句返回状态代码,但我显然不能在长时间运行的进程之前使用它,因为它将从函数中退出
注意:我的代码中没有实际使用time.sleep40。这只是为了子孙后代和南方科学院。它将返回相同的结果让compile\u元数据生成一个线程来处理长时间运行的任务,然后立即返回结果代码,即不等待线程完成。确保对可以生成的同时线程的数量进行一些限制
对于稍微更健壮和可扩展的解决方案,考虑一些类似于消息队列的解决方案,如
作为记录,一个简单的解决方案可能如下所示:import time
import threading
from flask import Flask, abort, jsonify
debug = True
app = Flask(__name__)
def long_running_task():
print 'start'
time.sleep(40)
print 'finished'
@app.route("/", methods=['POST'])
def compile_metadata():
# the long running process...
t = threading.Thread(target=long_running_task)
t.start()
# end the long running process
return jsonify({"success": True})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8082, debug=debug, threaded=True)
我可以通过使用multiprocessing.dummy.Pool实现这一点。在使用threading.Thread之后,它被证明是无用的,因为即使t.daemon=True,Flask仍然会等待线程完成 我实现了在长时间运行任务之前返回状态代码的结果,如:
#!/usr/bin/env python
import time
from flask import Flask, jsonify, request
from multiprocessing.dummy import Pool
debug = True
app = Flask(__name__)
pool = Pool(10)
def compile_metadata(data):
print("Starting long running process...")
print(data['user']['email'])
time.sleep(5)
print("Process ended!")
@app.route('/', methods=['POST'])
def webhook():
data = request.json
pool.apply_async(compile_metadata, [data])
return jsonify({"success": True}), 202
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8082, debug=debug, threaded=True)
当您希望快速从服务器返回响应,并且仍然要做一些耗时的工作时,通常应该使用某种共享存储(如Redis)来快速存储所需的所有内容,然后返回状态代码。所以请求很快就得到了满足 并有一个单独的服务器定期处理语义作业队列,以完成耗时的工作。然后在工作完成后从队列中删除该作业。也许还可以将最终结果存储在共享存储中。这是正常的方法,而且它的伸缩性非常好。例如,如果您的作业队列增长过快,单个服务器无法跟上,则可以添加更多服务器来处理该共享队列 但即使您不需要可伸缩性,理解、实现和调试它也是一个非常简单的设计。如果您的请求负载出现意外峰值,这只意味着您的独立服务器可能会彻夜运转。您可以放心,如果服务器关闭,您不会丢失任何未完成的工作,因为它们在共享存储中是安全的 但是,如果您让一台服务器完成所有工作,在后台异步执行长时间运行的任务,我想可能只是确保后台工作如下所示:
------------ Serving Responses
---- Background Work
---- ---- Serving Responses
---- Background Work
不是这样的:
------------ Serving Responses
---- Background Work
---- ---- Serving Responses
---- Background Work
否则,如果服务器在后台执行某些工作块,它可能对新请求没有响应,这取决于即使在请求负载很小的情况下,耗时的工作所需的时间。但是如果客户端超时并重试,我认为您仍然可以安全地执行双重工作。但是你不能避免失去未完成的工作。运行另一个线程是我的本能,如果烧瓶溶液不起作用,那么我肯定会这样做。我还将看一看celeryok——所以我看了另一条线,有趣的是没有骰子。烧瓶仍在等待线程完成。我也试过芹菜,但它需要一个中间人,而且更符合我的意愿。我选择了multiprocessing.dummy.Pool。我会写一个答案,给你和你的想法投赞成票:我实际上运行了上面的代码,当线程仍在运行时,它显然会立即返回。奇怪。。。我一字不差地复制了您的代码并开始了长时间运行的过程。。。过程结束了!127.0.0.1---[24/Mar/2017 12:14:06]POST/HTTP/1.1200-而不是127.0.0.1---[24/Mar/2017 12:40:33]POST/HTTP/1.1202-开始长时间运行流程。。。过程结束了!