Python - 为什么 SIGTERM 终止父进程,即使它只发送到子进程?

问题描述 投票:0回答:1

我是在 python 中处理信号的新手。我想使用 fastapi 运行服务器。在服务器中,有一个耗时的服务(代码中的url:“/run”)可能会被外部杀死(url:“/stop”)。

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pathos.multiprocessing import ProcessingPool
import os
import uvicorn
import signal
from sub import run_loop

app = FastAPI()

def run_py(**kwargs):
    i = kwargs['i']
    try:
        out = ProcessingPool().map(run, [[i]])[0]
    except SystemError as err:
        out = 114514

    return out

def run(args):
    re_fig = run_loop(args[0])
    return re_fig

@app.post("/run")
def run_main():
    i = 1
    out = run_py(i=i)
    return JSONResponse({"code": 200, "message": out})

@app.post("/stop")
def stop():
    with open("./pid.txt", "r") as f:
        pid = int(f.readline())
    os.kill(pid, signal.SIGTERM)

if __name__ == "__main__":
    uvicorn.run(app='test:app', host="0.0.0.0", port=1145, reload=False)

我在子进程中设置了一个 SIGTERM 处理程序:

import signal
import os
import time

def loop(i):
    pid = os.getpid()
    with open("./pid.txt", "w") as f:
        f.write(str(pid))

    while i < 30:
        i += 1
        print(f"sleep {i}")
    return i

def run_loop(i):
    def sigterm_handler(_signo, _stack_frame):
        print("stop!!!!!!!!!!!!")
        raise SystemError

    signal.signal(signal.SIGTERM, sigterm_handler)

    i = loop(i)
    return i

当我通过向“/stop”发送请求来触发

sigterm_handler
时,我期望仅停止子进程循环并引发
SystemError
,以便可以在主进程中将
out
设置为114514。好吧,这已经实现了,但是整个服务器也停止了:

INFO:     Started server process [108395]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:1145 (Press CTRL+C to quit)
sleep 2
sleep 3
sleep 4
sleep 5
sleep 6
stop!!!!!!!!!!!!
INFO:     127.0.0.1:57480 - "POST /stop HTTP/1.1" 200 OK
INFO:     127.0.0.1:57476 - "POST /run HTTP/1.1" 200 OK
INFO:     Shutting down
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
INFO:     Finished server process [108395] 

如何只杀死子进程而不终止整个服务器?

python signals fastapi
1个回答
0
投票

您可以将多处理的start_method更改为spawn方法,您的子进程将变得清晰(没有继承的信号处理程序,线程池和其他东西)。

@app.on_event("startup")
async def on_startup():
    multiprocessing.set_start_method('spawn')
© www.soinside.com 2019 - 2024. All rights reserved.