python global variable in fastApi not working as normal

Viewed 11814

I have a simple fastApi demo app which achieve a function: get different response json by calling a post api named changeResponse. The changeResponse api just changed a global variable, another api return different response through the same global variable.On local env,it works correctly, but the response always changed after i just call changeResponse once when i build this on docker.The code is as follows:

from typing import Optional
from fastapi import FastAPI
from util import read_json
import enum

app = FastAPI()

type = "00"
    
@app.post("/changeResponse")
async def handle_change_download_response(param:Optional[str]):
        global type
        type = param
        print("type is "+type)
        return {"success":"true"}

@app.post("/download")
async def handle_download(param:Optional[str]):
    print("get download param: "+param)
    if legalDownload(param):
        print("type is "+type)
        return read_json.readDownloadSuccessRes(type)
    else:
        return read_json.readDownloadFailRes()

def legalDownload(data:str)->bool:
    return True

the dockerfile is as follows:

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7

COPY ./app /app

what i except: call changeResponse param is 7, get response for 7, call changeResponse param is 8, get response for 8. what i get: call changeResponse param is 7,get reponse for 7,call changeReponse 8, sometime the response is 7, sometime is 8,impossible to predict

3 Answers

tiangolo/uvicorn-gunicorn-fastapi is based on uvicorn-gunicorn-docker image, which by defaults creates multiple workers. Excerpt from gunicorn_conf.py:

default_web_concurrency = workers_per_core * cores

Thus, the described situation arises because the request is processed by different workers (processes). Each of which has its own copy of the global variable

Update: If you want to change the count of workers, use the following environment variables:

  • WORKERS_PER_CORE: It will set the number of workers to the number of CPU cores multiplied by this value.
  • MAX_WORKERS: You can use it to let the image compute the number of workers automatically but making sure it's limited to a maximum.
  • WEB_CONCURRENCY Override the automatic definition of number of workers.

You can set it like:

docker run -d -p 80:80 -e WEB_CONCURRENCY="2" myimage

A more detailed description of these variables and examples here


If you want to share data between workers, pay attention to this topic.

Had the same issue and got is fixed without changing the workers.

app = FastAPI()

app.type = "00"

Which I think is the best option.

Ref with many thanks : fastapi/issues/592

I already known why:

the fastapi use uvicorn run the app, and use gunicorn to manage these uvicorn the gunicorn in docker container default starts 2*num_of_core + 1 workers to run these uvicorn,so i assume there are three app in the server,and the request was sented to random worker to handle. that's why the response is random reference:https://docs.gunicorn.org/en/stable/design.html

Related