GregH
GregH

Reputation: 12868

Why when I start uvicorn in my FastAPI service does my configuration method run twice?

I have written a service using fastapi and uvicorn. I have a main in my service that starts uvicorn (see below). In that main, the first thing I do is load configuration settings. I have some INFO outputs that output the settings when I load the configuration. I notice when I start my service, the configuration loading method seems to be running twice.

# INITIALIZE
if __name__ == "__main__":
    # Load the config once at bootstrap time. This outputs the string "Loading configuration settings..."
    config = CdfAuthConfig()
    print("Loaded Configuration")
    # Create FastAPI object
    app = FastAPI()
    # Start uvicorn
    uvicorn.run(app, host="127.0.0.1", port=5050)

The output when I run the service looks like:

Loading configuration settings...
Loading configuration settings...
Loaded Configuration

Why is the "CdfAuthConfig()" class being instantiated twice? It obviously has something to do with the "uvicorn.run" command.

Upvotes: 13

Views: 5974

Answers (2)

Peter Trcka
Peter Trcka

Reputation: 1521

I have found another solution. Split script into app_definition and run script:

The first file contains only the app definition (no executable script).

# main.py
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()
... # your app code goes here

To avoid double execution, you can run the app from another file.

# app_run.py
if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

This can be run from the command line: python app_run.py without the need to write uvicorn parameters.

Upvotes: 6

daniel
daniel

Reputation: 101

I had a similar setup and this behavior made me curious, I did some tests and now I see probably why.

Your if __name__ == "__main__": is being reached only once, this is a fact.

How can you test this. Add the following line before your if:

 print(__name__)

If you run your code as is, but adding the line I mentioned, it will print:

__main__  # in the first run

Then uvicorn will call your program again and will print something like:

__mp_main__  # after uvicorn starts your code again

And right after it will also print:

app  # since this is the argument you gave to uvicorn

If you want to avoid that, you should call uvicorn from the command line, like:

uvicorn main:app --reload --host 0.0.0.0 --port 5000  # assuming main.py is your file name

uvicorn will reload your code since you are calling it from inside the code. Maybe a work around would be to have the uvicorn call in a separate file, or as I said, just use the command line. If you don't wanna write the command with the arguments all the time, you can write a small script (app_start.sh)

I hope this helps you understand a little bit better.

Upvotes: 10

Related Questions