pythonpython-asynciofastapi

How to stop background tasks in a graceful shutdown of FastAPI


Whenever I gracefully shut down my FastAPI app by saving a file (with the --reload option), it waits for all background tasks to be complete before initiating shutdown.

uvicorn INFO:     Shutting down
uvicorn INFO:     connection closed
uvicorn INFO:     Waiting for background tasks to complete. (CTRL+C to force quit)

The problem is that my tasks will never be completed since I need to manually cancel them upon FastAPI shutdown. In the following example:

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup logic (if any)
    yield
    logger.info("Shutting down sessions")
    # Shutdown logic (if any)
    Session.close_all()

"Shutting down sessions" is never logged because it is waiting for all background tasks to be completed, which will never happen until I call Session.close_all(). How am I supposed to close my sessions so that FastAPI can properly shut down?


Solution

  • Referring to Corky's answer here

    You can patch Starlette's exit handler to customize its behavior. Since I am using FastAPI with multiple files I came up with this solution:

    from uvicorn.main import Server
    from fastapi import FastAPI
    ....
    
    app = FastAPI()
    app.should_exit = False
    original_handler = Server.handle_exit
    
    def handle_exit(*args, **kwargs):
        app.should_exit = True
        original_handler(*args, **kwargs)
    
    Server.handle_exit = handle_exit
    

    Additionally, as you mentioned, you can call Session.close_all() inside the handle_exit function.