fastapi icon indicating copy to clipboard operation
fastapi copied to clipboard

asyncio.wait_for doesn't time out as expected

Open liyunrui opened this issue 2 years ago • 1 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the FastAPI documentation, with the integrated search.
  • [X] I already searched in Google "How to X in FastAPI" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to FastAPI but to Pydantic.
  • [X] I already checked if it is not related to FastAPI but to Swagger UI.
  • [X] I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • [X] I commit to help with one of those options 👆

Example Code

d

Description

d

Operating System

macOS

Operating System Details

d

FastAPI Version

fastapi==0.89.1

Python Version

3.9

Additional Context

@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)
    print("adfadsfasdf")
    # response.headers["Test middleware"] = str(random.randint(1, 1000))
    return response


REQUEST_TIMEOUT_ERROR = 1.0 # seconds to wait for
from fastapi.responses import JSONResponse
from starlette.status import HTTP_504_GATEWAY_TIMEOUT

#Adding a middleware returning a 504 error if the request processing time is above a certain threshold
@app.middleware("http")
async def timeout_middleware(request: Request, call_next):
    try:
        start_time = time.time()
        return await asyncio.wait_for(call_next(request), timeout=REQUEST_TIMEOUT_ERROR)

    except asyncio.TimeoutError:
        process_time = time.time() - start_time
        res = timeout_fallback(process_time)
        return res

def timeout_fallback(process_time):
    response = JSONResponse({'detail': 'Request processing time excedeed limit',
                             'processing_time': process_time},
                            status_code=HTTP_504_GATEWAY_TIMEOUT)
    return response

Does anyone know why? It's super weird. Basically, you need to have two @app.middleware("http"). Otherwise, the timeout exception won't work.

liyunrui avatar Jan 13 '23 10:01 liyunrui

Have you tried using ASGI Middlewares?

odiseo0 avatar Jan 13 '23 14:01 odiseo0

Quite peculiar! app.middleware code is quite straightforward, however you're soon getting out of fastapi territory into starlette, IIRC. aside: are you clear about the order that the middlewares are applied in?

Anyway, please dig deeper and figure it out. It's going to be fun! 🚀

dimaqq avatar Jan 18 '23 01:01 dimaqq

Something to look forward to in the future: https://docs.python.org/3.12/library/asyncio-task.html#timeouts

devoredevelops avatar Jan 27 '23 23:01 devoredevelops