Python 从Flask返回HTTP状态代码,但不返回 上下文 我有一个名为server.py的服务器,它充当GitLab的提交后webhook。 在server.py中,有一个长时间运行的进程约40秒 SSCCE 问题陈述

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)

GitLab的Webhook希望返回代码能够快速返回。因为我的webhook在40秒后或大约40秒后返回;GitLab会发送一次重试,在循环中发送我的长时间运行的进程,直到GitLab尝试了太多次

问题 我是否能够将状态代码从Flask返回到GitLab,但仍然运行长时间运行的流程

我尝试添加一些类似的内容:

...
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-开始长时间运行流程。。。过程结束了!