繁体   English   中英

如何在Flask中运行后台计时器

[英]How to run a background timer in Flask

我正在尝试编写一个Flask应用程序,该应用程序在Kubernetes中运行时尤其是在正常关机时运行正常

因此,我需要代码:

  • 收到关机信号
  • 启动“关机计时器”
  • 继续正常处理请求,直到时间到了
  • 然后关闭自己

到目前为止,我所得到的是:

from flask import Flask, abort
import signal
import time
app = Flask(__name__)
shuttingDown = False

def exit_gracefully(self, signum):
    app.logger.error('Received shutdown signal. Exiting gracefully')
    global shuttingDown
    shuttingDown = True
    # TODO: wait for some time here to ensure we are not receiving any more
    # traffic
    time.sleep(20)
    exit(0)

signal.signal(signal.SIGTERM, exit_gracefully)

@app.route("/")
def hello():
        return "Hello World!"

@app.route("/_status/liveness")
def liveness():
        return "I am alive"

@app.route("/_status/readiness")
def readiness():
        if not shuttingDown:
            return "I am ready"
        else:
            abort(500, 'not ready anymore')

除了我发送“ shutdown”信号后,上述“工作”正常,对“ /”的常规请求均未响应,即使我们仍处于关闭“宽限期”(上述代码中为20秒)内。

似乎对“ time.sleep()”的调用是同步的。

有谁知道使这种“异步”的方法吗? 这样,该应用就可以继续处理请求,直到时间到了为止。

猜测您正在使用内置的Flask开发服务器。 Flask和Django中的此类内置开发服务器,或标准库中基于Web服务器或WSGI服务器的任何内容,均不适用于生产系统,并且通常无法正确处理信号的关闭。

因此,您实际上应该使用适当的生产级WSGI服务器,例如Apache / mod_wsgi(mod_wsgi-express),gunicorn或uWSGI。 这些都正确地处理了信号,并且开发服务器没有问题,它们忽略了导致容器关闭延迟的信号,当关闭超时发生时,它最终被Kubernetes杀死。

这适用于内部服务器。 需要注意的是,有一个/ _shutdown URL可以关闭服务器,这对恶意关闭很开放。 如果这不是你想要的,然后取出requests.post()并取消os._exit() 当然, @app.route("/_shutdown")删除@app.route("/_shutdown")和该函数。

from flask import Flask, abort, request
import signal
import threading
import time
import os
import requests
app = Flask(__name__)
shuttingDown = False


def exit_call():
    time.sleep(20)
    requests.post("http://localhost:5420/_shutdown")
    # os._exit(0)


def exit_gracefully(self, signum):
    app.logger.error('Received shutdown signal. Exiting gracefully')
    global shuttingDown
    shuttingDown = True
    # TODO: wait for some time here to ensure we are not receiving any more
    # traffic
    _et = threading.Thread(target=exit_call)
    _et.daemon = True
    _et.start()


signal.signal(signal.SIGTERM, exit_gracefully)


@app.route("/")
def hello():
        return "Hello World!"


@app.route("/_status/liveness")
def liveness():
        return "I am alive"


@app.route("/_shutdown", methods=["POST"])
def shutdown():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        return "Not a werkzeug server"
    func()
    return "shutdown"


@app.route("/_status/readiness")
def readiness():
        if not shuttingDown:
            return "I am ready"
        else:
            abort(500, 'not ready anymore')


app.run(port=5420)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM