[Python] About the maximum recursion error in FastAPI

Discussão em 'Python' iniciado por Stack, Fevereiro 19, 2025.

  1. Stack

    Stack Membro Participativo

    I am building an application using FastAPI+Sqlalchemy+Mysql, and when I do a stress test,I get an Asgi exception error:

    [ERROR] Exception in ASGI application,
    RecursionError: maximum recursion depth exceeded while calling a Python object.


    I can definitely have :

    1. I did not call any recursive function
    2. I have tried both alchemy and mysql_connector to query the database but the error still exists.

    The code is here:

    My main.py as follows


    def create_app()->FastAPI:
    app = FastAPI(debug = False)

    register_cors(app)

    app.include_router(admin_router)

    register_exception(app)

    register_token_validate(app)

    return app


    ***def register_cors(app:FastAPI):
    @app.middleware("http")
    async def cors(request:Request, call_next):
    app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    )
    response = await call_next(request)
    response.headers["access-control-allow-credentials"] = "true"
    response.headers["access-control-allow-origin"] = "*"
    response.headers["access-control-allow-methods"] = "*"
    return response***

    def register_exception(app:FastAPI):

    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
    errType = (exc.errors())[0]["type"]
    detail = (exc.errors())[0]
    type = errType.split(".")
    if type[0] == "value_error":
    return JSONResponse(
    status_code=422,
    content={"code": 422,"msg": "value error", "errinfo_type":detail}
    )
    elif type[0] == "type_error":
    return JSONResponse(
    status_code=422,
    content={"code": 422,"msg": "type error", "errinfo_type":detail}
    )
    else:
    return JSONResponse(
    status_code=422,
    content={"code": 422,"msg": "server error", "errinfo_type":detail}
    )


    @app.exception_handler(Exception)
    async def all_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
    status_code=500,
    content={"code": 500,"msg": "server error", "errinfo_type":None}
    )

    def register_token_validate(app: FastAPI):
    @app.middleware("http")
    async def token_validate(request: Request, call_next):
    excludeUrlL = [
    "/v1/login",
    "/docs",
    "/redoc"
    ]

    if (request.url.path not in excludeUrlL) and (request.method != "OPTIONS"):
    res = security.validate_token(request.headers.get("token"), request.headers.get("request_time"))
    if res['status'] == "success":
    response = await call_next(request)
    response.headers["access-control-allow-credentials"] = "true"
    response.headers["access-control-allow-origin"] = "*"
    response.headers["access-control-allow-methods"] = "*"
    return response
    elif res['status'] == "failed":
    return JSONResponse(
    status_code=401,
    content={"code": 401,"msg": "token expired"}
    )
    elif res['status'] == "updated":
    response = await call_next(request)
    response.headers["token"] = res['payload']
    response.headers["access-control-allow-credentials"] = "true"
    response.headers["access-control-allow-origin"] = "*"
    response.headers["access-control-expose-headers"] = "token"
    response.headers["access-control-allow-methods"] = "*"
    return response
    else:
    response = await call_next(request)
    response.headers["access-control-allow-credentials"] = "true"
    response.headers["access-control-allow-origin"] = "*"
    response.headers["access-control-allow-methods"] = "*"
    return response

    app = create_app()

    if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app="main:app", host="0.0.0.0", port=8000, reload=True, debug=False)


    security.py


    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    from datetime import datetime, timedelta, tzinfo
    from db.DbSession import session
    from sqlalchemy import text

    from config import config
    from core.logger import logger
    from core import util
    import pytz


    def validate_token(token, request_time):
    if not token:
    return {"status":"failed", "payload":None, "msg": "token is required"}

    if not request_time:
    return {"status":"failed", "payload":None, "msg": "request_time is required"}

    sql = "select id, mobile, token, expired_time, last_request_time from my_user_table where token = :token limit 1"
    rp = session.execute(text(sql), {"token":token})
    res = [dict(r.items()) for r in rp]

    if not res:
    return {"status":"failed", "payload":None, "msg": "token error"}

    nowStamp = datetime.now().timestamp()
    expired_timeStamp = res[0]['expired_time'].timestamp()

    if nowStamp > expired_timeStamp:
    return {"status":"failed", "payload":None, "msg": "token is expired"}

    if (int(request_time) - int(res[0]['last_request_time'])) > 600:
    return {"status":"updated", "payload":token, "msg": "token is updated"}
    else:
    return {"status":"success", "payload":None, "msg": "token is valid"}




    session.py

    from sqlalchemy import create_engine
    from sqlalchemy.orm import Session
    from sqlalchemy.pool import NullPool

    engine = create_engine(config.DbUrl, echo = False, poolclass=NullPool)
    session = Session(engine)


    api.py

    @router.get("/v1/getCompany", summary="get company information")
    async def getCompany(id:int):
    sql = "select * from my_company_table c where c.id = :id"
    rp = session.execute(text(sql), {"id":id})
    res = [dict(r.items()) for r in rp]
    session.commit()
    return util.resp_200(200, 'get company information success', res)


    When I call this interface /v1/getCompany continuously, I get the above error

    [ERROR] Exception in ASGI application
    Traceback (most recent call last):
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 388, in run_asgi
    result = await app(self.scope, self.receive, self.send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/fastapi/applications.py", line 179, in __call__
    await super().__call__(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 86, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 142, in simple_response
    await self.app(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 86, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 142, in simple_response
    await self.app(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 86, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)

    ..........


    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 86, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 142, in simple_response
    await self.app(scope, receive, send)
    File "/root/.cache/pypoetry/virtualenvs/facli-zsB1kvQc-py3.8/lib/python3.8/site-packages/starlette/middleware/cors.py", line 74, in __call__
    headers = Headers(scope=scope)
    File "/usr/local/lib/python3.8/typing.py", line 873, in __new__
    obj = super().__new__(cls)
    RecursionError: maximum recursion depth exceeded while calling a Python object



    I have looked up all the relevant questions, but unfortunately have not found the answers, Now I can only suspect that it is a problem with FastAPI or Starlette, who can give me a solution to the problem, thanks a lot.

    After testing, I can solve this problem in this way:sys.setrecursionlimit(9000000), but I think that this should not be the best solution for this kind of problem

    Continue reading...

Compartilhe esta Página