Azure / azure-functions-python-worker

Python worker for Azure Functions.
http://aka.ms/azurefunctions
MIT License
335 stars 103 forks source link

[BUG] Azure Function AsgiMiddleware Not Responding #1104

Closed yks0000 closed 1 year ago

yks0000 commented 2 years ago

Investigative information

Please provide the following:

Repro steps

Provide the steps required to reproduce the problem:
  1. Create a new Function App of type HTTP trigger and the following code in __init__.py:
import azure.functions as func
import time
import nest_asyncio
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

nest_asyncio.apply()

app = FastAPI(title="FastAPI on Azure")
app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    return func.AsgiMiddleware(app).handle(req, context)

@app.get("/")
async def root():
    return {"message": "Hello from Azure Function"}

Complete code including config is available in GitHub repo: https://github.com/yks0000/az-function-fastapi/tree/azure-worker-issue To start function app: func host start --verbose

Expected behavior

Provide a description of the expected behavior.

It should return a response when we access http://0.0.0.0:7071/

Actual behavior

Provide a description of the actual behavior observed.

No response and running forever.

Known workarounds

Provide a description of any known workarounds.

No workaround but If we stop using middleware (as below), it works, but the requirement is to use middleware.

Middleware Doc: https://fastapi.tiangolo.com/tutorial/middleware/

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

Contents of the requirements.txt file:

Provide the requirements.txt file to help us find out module related issues.
azure-common
azure-core
azure-functions
fastapi
nest-asyncio

Related information

Provide any related information
ramya894 commented 1 year ago

@yks0000 We will check this issue with our next level team and update you.

ramya894 commented 1 year ago

@vrdmr Can you please have a look into this issue.

yks0000 commented 1 year ago

@vrdmr @YunchuWang Any update on this please?

ramya894 commented 1 year ago

@YunchuWang Could you please have a look into the above issue

tonybaloney commented 1 year ago

@yks0000 I'll clone your repo and isolate the issue.

There is a new API for the sample that removes the need for nest-asyncio and changes the main function to:

async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    return await func.AsgiMiddleware(app).handle_async(req, context)
tonybaloney commented 1 year ago

@yks0000 I've submitted a PR to your sample with the changes to the sample for v1.12 of the functions library

https://github.com/yks0000/az-function-fastapi/pull/1

This fixes the hanging process problem, but the app returns no response and if the add_process_time_header() function is commented out it works correctly.

I'll continue looking at this to see how the middleware chains calls to other middleware.

tonybaloney commented 1 year ago

Looking deeper into the issue with a debugger, when the custom middleware is added, the http.response.body message is never sent to the Azure functions library code for handling ASGI applications. I don't think it's an issue specifically with the middleware, but having 2 items in the FastAPI middleware collection seems to cause some issue

2022-11-29T02:35:00.066Z] Received {'type': 'http.response.start', 'status': 200, 'headers': [(b'content-length', b'39'), (b'content-type', b'application/json')]} from ASGI worker.
[2022-11-29T02:35:00.066Z] Received {'type': 'http.response.body', 'body': b'{"message":"Hello from Azure Function"}'} from ASGI worker.
yks0000 commented 1 year ago

Thanks @tonybaloney for checking this.

tonybaloney commented 1 year ago

I've submitted a fix to the related package, it might take a while for this to roll through. https://github.com/Azure/azure-functions-python-library/pull/153

In the meantime only 1 piece of middleware is supported.