24

When trying to host an API on App Engine, the following error keeps coming up. The program used to run on Flask which was working but very slow.

Error:

"Traceback (most recent call last):
  File "/env/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 134, in handle
    self.handle_request(listener, req, client, addr)
  File "/env/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 175, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
TypeError: __call__() missing 1 required positional argument: 'send'
"

Docker File:

FROM gcr.io/google_appengine/python

RUN apt-get update && apt-get install -y ffmpeg

# Create a virtualenv for dependencies. This isolates these packages from
# system-level packages.

RUN virtualenv /env -p python3.7

# Setting these environment variables are the same as running
# source /env/bin/activate.

ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH

ADD requirements.txt /app/requirements.txt
RUN pip install -r /app/requirements.txt

# Add the application source code.

ADD . /app

CMD gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app

app.yaml

runtime: custom
env: flex
entrypoint: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
service: encoder

runtime_config:
  python_version: 3

handlers:

- url: /.*
  script: auto
Dustin Ingram
  • 20,502
  • 7
  • 59
  • 82
Josh Bello
  • 261
  • 1
  • 2
  • 3
  • 3
    The error basically says you are trying to run FastAPI as WSGI which is not right and acceptable because FastAPI is only compatible with ASGI. See [this](https://stackoverflow.com/questions/63099843/how-can-i-fix-fastapi-application-error-on-apache-wsgi) – Yagiz Degirmenci Aug 15 '20 at 10:29
  • 1
    Thanks @YagizcanDegirmenci I'll try running it with just Uvicorn – Josh Bello Aug 15 '20 at 18:13
  • So it runs, but now I get this error, `"[error] 33#33: *92500 connect() failed (111: Connection refused) while connecting to upstream, client: 216.58.212.244, server: ` – Josh Bello Aug 17 '20 at 09:43

5 Answers5

34

As Dustin said I found out that worker class need to be changed. Try the below one.

gunicorn -k uvicorn.workers.UvicornWorker main:app

Found this on github issues

Akshith
  • 463
  • 5
  • 10
7

App Engine requires your main.py file to declare an app variable which corresponds to a WSGI Application.

Since FastAPI is an asynchronous web framework, it is not compatible with WSGI (which is synchronous).

Your best option would be to use a service like Cloud Run, which would allow you to define your own runtime and use an asynchronous HTTP server compatible with FastAPI.

Dustin Ingram
  • 20,502
  • 7
  • 59
  • 82
  • I am trying to find any info on how to configure Cloud Run to use an asynchronous HTTP server. Can anyone please guide me to the appropriate docs? Thanks. – Bellave Jayaram Dec 22 '20 at 19:25
  • @BellaveJayaram Since Cloud Run allows you to use any container image, there is nothing specific required to use an async HTTP server. If there was a particular server you wanted to use and weren't sure how to get started, I'd recommend asking a new question instead of leaving a comment here. – Dustin Ingram Dec 23 '20 at 18:05
  • This is the best answer since it also explains why FastAPI requires a uvicorn worker. Thank you. – Nur L May 06 '22 at 15:59
4

I ran into the same issue when I want to deploy a FastAPI app to Heroku. Indeed, you can't use uvicorn (which is the ASGI framework that FastAPI is using) with Heroku that uses gunicorn.

However, by adding a uvicorn worker to gunicorn then it works!:

gunicorn api:app --bind 0.0.0.0:$PORT --worker-class uvicorn.workers.UvicornWorker

Antoine Krajnc
  • 1,163
  • 10
  • 29
1

In the Starlette code, I found a reference to a2wsgi. And it looks like it is going in both directions (wsgi<>asgi).

I gave it a try and it worked well for me:

from a2wsgi import ASGIMiddleware
wsgi_app = ASGIMiddleware(app)
# use this wsgi instead of your app
FLemaitre
  • 503
  • 2
  • 9
0

I solved it by putting python main.py as the build command and setting my uvicorn command in the main.py as uvicorn.run("main:app", host="0.0.0.0", port=8080)