pythonpython-3.xdockerfastapiuvicorn

Python global variable in FastAPI not working as normal


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 changes 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


Solution

  • 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:

    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.