Reputation: 151
I had checked PyInstaller and FastAPI (maximum recursion depth exceeded) and Pyinstaller-compiled Uvicorn server does not start correctly
FastAPI demo main.py
:
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"hello": "world"}
if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=58000, reload=False)
Run pyinstaller first pyinstaller -F main.py --clean
and add hidden_imports
in spec:
hidden_imports=[
'uvicorn.logging',
'uvicorn.loops',
'uvicorn.loops.auto',
'uvicorn.protocols',
'uvicorn.protocols.http',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.websockets',
'uvicorn.protocols.websockets.auto',
'uvicorn.lifespan',
'uvicorn.lifespan.on',
]
It works good, but the app must be string when workers greater than 1:
WARNING: You must pass the application as an import string to enable 'reload' or 'workers'.
So I change to:
if __name__ == '__main__':
uvicorn.run("main:app", host="0.0.0.0", port=58000, reload=False, workers=2)
After doing that, I ran the app dist/main
and it created many apps like below, using 100% CPUs and 100% memories rapidly:
Works on Python 3.8.3 and pyinstaller 4.0
Upvotes: 2
Views: 9837
Reputation: 4188
It is important to call (on Windows) mutiprocessing.freeze_support()
in the beginning, see official docs.
import multiprocessing
...
...
...
if __name__ == '__main__':
mutiprocessing.freeze_support()
uvicorn.run("main:app", host="0.0.0.0", port=58000, reload=False, workers=2)
Additionally, it might be needed to add the module main
as a hidden import.
Upvotes: 5
Reputation: 693
It looks like an infinite recursion to me. I suspect the cause is related to the self-reference at main:app
and some PyInstaller sys
dark magic that sets __name__
as __main__
.
I recommend moving app
into a separate module and referencing it from that module in uvicorn.run()
:
# app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"hello": "world"}
# main.py
import uvicorn
if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=58000, reload=False, workers=2)
Also, don't forget to add app.py
as a hidden import for PyInstaller:
hidden_imports=[
'uvicorn.logging',
'uvicorn.loops',
'uvicorn.loops.auto',
'uvicorn.protocols',
'uvicorn.protocols.http',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.websockets',
'uvicorn.protocols.websockets.auto',
'uvicorn.lifespan',
'uvicorn.lifespan.on',
'app',
]
Upvotes: 3