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!
)
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