json_logging.init_fastapi() can only run once per process. This example puts the app and its initialisation in one
module, app/main.py, and shows how to start it with uvicorn without importing that module twice.
Run these from the example/fastapi_startup directory.
-
Import string, started by uvicorn (recommended):
python -m uvicorn app.main:app --port 8000
uvicorn imports
app.mainonce, so the module body runs once. Recommended because it also works with--reloadand--workers(see below). -
Pass the app object from a separate launcher,
run.py, that does not contain the app:import uvicorn from app.main import app if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=8000)
python run.py
uvicorn receives the app object, not an import string, so it does not import
app.mainagain.
- Use the import-string pattern (1) for
--reloador--workers N. uvicorn needs an import string for both; with an app object it logs "You must pass the application as an import string to enable 'reload' or 'workers'" and exits. - Passing the app object (2) suits a simple single-process start.
- With reload or several workers, each worker is its own process and imports
app.mainonce, soinit_fastapi()runs once per worker process. That is expected. The error only occurs when the same process initialises twice.
# app/main.py, executed directly
...
if __name__ == "__main__":
uvicorn.run("app.main:app") # imports app.main again, so init_fastapi() runs twiceThis raises RuntimeError: Can not call init more than once (issue #106). The module runs once as __main__ and
again as app.main. Either use one of the working patterns above, or keep the launch code out of the module that
creates the app.
From this directory:
python -m pytest ../../tests/test_fastapi_startup.py -qor, from the repository root, python -m pytest tests/test_fastapi_startup.py -q.