我有一个 Python Flask 应用程序:
from flask import Flask, Response
import signal
app = Flask("myapp")
def exit_gracefully(*args):
print("Doing something here")
signal.signal(signal.SIGINT, exit_gracefully)
signal.signal(signal.SIGTERM, exit_gracefully)
@app.route("/myendpoint")
def myendpoint():
print("Doing something here")
return Response("Everything is fine", status=200, mimetype="application/json")
这个应用程序由gunicorn运行,使用经典的
wsgi.py
文件和systemd服务:
[Unit]
Description=myservice
[Service]
User=root
Group=root
WorkingDirectory=/opt/myservice
ExecStart=/opt/myservice/run.sh
[Install]
WantedBy=multi-user.target
#!/bin/bash
source env/bin/activate
env/bin/gunicorn --bind unix:gunicorn.sock --workers 1 --timeout 10 wsgi:app
我需要拦截发送到服务的SIGTERM信号,因为我需要执行一些清理和中断(特别是设置
threading.Event()
标志)
但是,问题是,当我输入
systemctl stop myservice
时,服务会在关闭前挂起 30 秒(这可能是gunicorn 的 graceful_timeout
设置),而不是像我打算的那样立即关闭。
在查看gunicorn的源代码时,我注意到Worker类使用信号处理程序来优雅地关闭自身:
# gunicorn/workers/base.py:173
signal.signal(signal.SIGTERM, self.handle_exit)
我的猜测是,由于每个信号只能使用一个处理程序,因此我将使用我自己的处理程序覆盖该处理程序。 但我仍然需要两个处理程序,我的处理程序用于完成清理操作,默认的处理程序用于让 Gunicorn 工作人员正确停止。
也许值得一提的是,当我在 shell 中运行
run.sh
并向其发送 SIGINT(按 Ctrl+C)时,我的应用程序立即停止,尽管 Gunicorn 也为其实现了一个处理程序。
关于我应该如何进行有什么想法吗?我想过在我自己的处理程序中调用函数
handle_exit
,但由于我的代码是“gunicorn-agnostic”,我不知道应该如何做到这一点。我应该更改应用程序的设计吗?
我也有同样的问题。当收到
SIGTERM
时,我的工作人员不会停止执行。就我而言,我正在与 Flask 应用程序一起运行一个线程。我正在接收信号并成功停止线程,但gunicorn并没有停止。解决方案是在 exit(0)
之后添加 thread.join()
语句。
我假设如果没有退出代码,gunicorn 会以某种方式认为该进程仍然存在。
from flask import Flask, Response
import signal
import time
import threading
app = Flask("myapp")
@app.route("/myendpoint")
def myendpoint():
print("Doing something here")
return Response("Everything is fine", status=200, mimetype="application/json")
must_stop = False
def sleppy_thread():
while True:
time.sleep(0.1)
if must_stop:
break
def exit_gracefully(*args):
global must_stop
must_stop = True
signal.signal(signal.SIGINT, exit_gracefully)
signal.signal(signal.SIGTERM, exit_gracefully)
sleepy_thread = threading.Thread(target=sleppy_thread)
sleepy_thread.start()
sleepy_thread.join()
exit(0)