본문 바로가기

Software Engineering/Python

fastapi get 요청으로 app 종료하기

* 어플리케이션 종료에 os._exit 또는 sys.exit(0)를 사용할 수 있음

 

* sys.exit()는 현재 실행 중인 스레드를 종료하는 함수로 내부적으로 SystemExit 예외를 발생시켜 종료를 처리함

해당 예외를 핸들링하는 핸들러가 있다면 해당 핸들러가 실행되고, 일반적으로는 finally 블록이나 atexit 모듈을 사용하여 등록된 종료 핸들러가 실행된다. 즉, 연관된 이벤트 핸들러가 동작하므로 정상적인 종료 절차를 밟고 종료할 때 사용한다. 

 

* os._exit(0) 현재 실행 중인 프로세스를 즉시 종료한느 함수로 운영체제 레벨에서 프로세스를 종료한다.

실행 즉시 프로세스가 종료되며, finally 블록이나 atexit 모듈을 사용하여 등록된 핸들러가 실행되지 않음. 즉시 종료가 필요한 경우나 자식 프로세스에서 호출하여 부모 프로세스에 영향을 미치지 않게 종료할 때 상요한다.

 

일반적으로 sys.exit(0)으로 종료하는 것이 안전하게 어플리케이션을 종료하는 방법이다.

아래와 같이 get 명령으로 어플리케이션 종료 요청을 받고, 새로운 스레드를 생성하여 해당 스레드에서 system을 종료하는 절차를 실행할 수 있다. 이 경우 app call의 응답은 즉시 반환되고, 필요한 프로세스 수행 후 어플리케이션이 종료된다.

 

from fastapi import FastAPI, Request
import os
import sys
import threading

app = FastAPI()

@app.get("/shutdown")
async def shutdown():
    shutdown_thread = threading.Thread(target=sys.exit, args=(0,))
    shutdown_thread.start()
    return {"message": "Server is shutting down..."}

@app.get("/")
async def read_root():
    return {"message": "Hello World"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

 

위 코드로 실행하면 실제 예상대로 동작하지 않음

 

from fastapi import FastAPI
from fastapi import Request, Response
import uvicorn
import threading
import os
import signal

app = FastAPI()
uvicorn_server = None

@app.get("/shutdown")
async def shutdown(request: Request):
def stop_server():
os.kill(os.getpid(), signal.SIGINT)

threading.Thread(target=stop_server).start()
return {"message": "Server is shutting down..."}

if __name__ == "__main__":
config = uvicorn.Config("main:app", host="0.0.0.0", port=8000, log_level="info")
uvicorn_server = uvicorn.Server(config)
uvicorn_server.run()