Search code examples
pythonfastapiuvicorn

Re-running an initialization function for each api reload


I am currently running an api project (fastapi served with uvicorn) where at startup a series of initializations are done.

If I set reload=True as an argument to my uvicorn startup function, my api correctly recognizes code changes and reloads. The issue is that I don't get the initializations when reloading the api, and this ends up breaking my workflow and effectively blocking me from using what I consider a very useful feature.

Example:

# fastapi app object is located in another module

def main() -> None:
    various_initializations()


if __name__ == "__main__":
    main()
    uvicorn.run("my.project.location.for:app", host="0.0.0.0", port=my_port, reload=True)

In this case I need my main function to be run at each reload.

Edit:

Testable example

main.py

import uvicorn

from my_class import MyClass


def init_stuff() -> None:
    MyClass.initialize()


if __name__ == "__main__":
    init_stuff()
    uvicorn.run("api:app", host="0.0.0.0", port=10000, reload=True)

my_class.py

class MyClass:
    initialized = False
    
    @staticmethod
    def initialize() -> None:
        MyClass.initialized = True

    @staticmethod
    def do_stuff() -> None:
        if not MyClass.initialized:
            raise ValueError("not initialized!")

        print("doing stuff")

api.py

from fastapi import FastAPI

from my_class import MyClass

app = FastAPI()


@app.get("/stuff")
def api_stuff() -> None:
    return MyClass.do_stuff()

When reload=False, if I hit the /stuff endpoint I get a correct behavior (doing stuff is printed on the terminal). With reload=True I get an exception indicating that MyClass hasn't been initialized (ValueError: not initialized!)


Solution

  • as @MatsLindh suggested, the (a?) way to do it is to hook on the startup event of fastapi, making the initialization run on each reload.

    my main.py file now looks like this:

    import uvicorn
    
    from my_class import MyClass
    from api import app
    
    @app.on_event("startup")
    def init_stuff() -> None:
        MyClass.initialize()
    
    
    if __name__ == "__main__":
        uvicorn.run("api:app", host="0.0.0.0", port=10000, reload=True)
    

    Happy api noises