Search code examples
pythonpython-asynciofastapiasgi

How to stop a loop on shutdown in FastAPI?


I have a route / which started an endless loop (technically until the websocket is disconnected but in this simplified example it is truly endless). How do I stop this loop on shutdown:

from fastapi import FastAPI

import asyncio

app = FastAPI()
running = True

@app.on_event("shutdown")
def shutdown_event():
    global running
    running = False

@app.get("/")
async def index():
    while running:
        await asyncio.sleep(0.1)

According to the docs @app.on_event("shutdown") should be called during the shutdown, but is suspect it is called similar to the lifetime event which is called after everything is finished which is a deadlock in this situation.

To test:

  1. i run it as uvicorn module.filename:app --host 0.0.0.0
  2. curl http://ip:port/
  3. then stop the server (pressing CTRL+C)

and you see that it hangs forever since running is never set to false because shutdown_event is not called. (Yes you can force shutdown by pressing CTRL+C)


Solution

  • import signal
    import asyncio
    from fastapi import FastAPI
    
    app = FastAPI()
    running = True
    
    def stop_server(*args):
        global running
        running = False
    
    @app.on_event("startup")
    def startup_event():
        signal.signal(signal.SIGINT, stop_server)
    
    @app.get("/")
    async def index():
        while running:
            await asyncio.sleep(0.1)
    

    Source: https://github.com/tiangolo/fastapi/discussions/9373#discussioncomment-5573492

    Setting up and catching the SIGINT signal allows to catch the first CNTR+C. This will set running to False which ends the loop in index(). Terminating the running request allowing the server to shutdown.