1

I wrote a simple custom Middleware as below:

class LoggingMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)

    async def dispatch(self, request, call_next):
        user_token = request.headers.get("x-token")
        req_id = time_ns()
        try:
            user_phone_number = decode(user_token, JWT_SECRET_KEY, algorithms=[HASH_ALGORITHM]).get("phone_number")
        except:
            user_phone_number = ''
        req_body = await get_json(request)
        reqb = dumps(req_body.decode('utf-8', 'ignore'), ensure_ascii=False)
        self.req_logger.info()

        response_time = 0
        try:
            s = time.time()
            resp = await call_next(request)
            response_time = round(time.time() - s, 2)
        except:
            self.error_logger.error()
            raise CustomException(
                details=ErrorResponseSerializer(
                    )
                ),
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        resp_body = b""
        async for item in resp.body_iterator:
            resp_body += item
        respb = dumps(resp_body.decode('utf-8', 'ignore'), ensure_ascii=False)
        if resp.status_code != 200:
            self.error_logger.error()
        return Response(
            content=resp_body,
            status_code=resp.status_code,
            headers=dict(resp.headers),
            media_type=resp.media_type
        )

and in one of my endpoints I wrote this functionality:

@router.get("/statistics/contract/count/", response_model=StatisticsCountsResponseSerializer)
def get_contract_count(
        province: str = None,
        dashboard_status: DashboardContractStatus = None,
        status: ContractStatus = None,
        csv: int = 0,
        context: Context = Depends(get_context)):
    repository = PostgresContractRepository(context=context)
    result = repository.get_counts(PROVINCES.get(province), dashboard_status, status)
    if not csv:
        return StatisticsCountsResponseSerializer.parse_obj({"count": result})
    else:
        filename = f"contract_counts_{int(datetime.datetime.utcnow().timestamp())}.csv"
        return StreamingResponse(
            # get_csv() yield an string which has csv format: yield "name,fmaily\nemad,emad"
            get_csv(),
            media_type="text/csv",
            headers={"Content-Disposition": f'attachment; filename="{filename}"'}
        )

when I send the request to this endpoint I gave this error in postman:

<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>

When I remove my middleware, everything is right and I got the excpected response. Maybe its useful to know that in other endpoints I return FileResponse and with the Middleware everything works fine. Just with StreamingResponse and Middleware I cannot get response.

Edit #1

After reading one of my comments, in this link, I change my code to this one:

async def dispatch(self, request, call_next):
    # self.check_authorization(request)
    user_token = request.headers.get("x-token")
    try:
        user_phone_number = decode(user_token, JWT_SECRET_KEY, algorithms=[HASH_ALGORITHM]).get("phone_number")
    except:
        user_phone_number = ''

    details = {
        "token": {
            "phone_number": user_phone_number
        },
        "request": {
            "id": time_ns(),
            "url_path": request.url.path,
            "query_params": request.query_params,
            "path_params": request.path_params
        },
        "response": {
            "duration": 0.0,
            "status_code": 200,
            "exception": None
        }
    }

    request_body = await get_json(request)
    try:
        s = time.time()
        response = await call_next(request)
        details["response"]["duration"] = round(time.time() - s, 2)
    except:
        self.error_logger.error(
            Logger.message_formatter(
                request_id=details.get("request").get("id"),
                path=request.url.path,
                token_phone_number=user_phone_number,
                query_params=request.query_params,
                path_params=request.path_params,
                body=request_body.decode('utf-8', 'ignore')
            )
        )
        self.error_logger.error(
            Logger.message_formatter(
                request_id=details.get("request").get("id"),
                path=request.url.path,
                message=traceback.format_exc(),
                status=500
            )
        )
        raise CustomException(
            details=ErrorResponseSerializer(
                metadata=MessageResponseSerializer(
                    type=MessageTypeEnum.error,
                    text=MessageTextResponseSerializer(
                        text="internal server error",
                        translate="..."
                    )
                )
            ),
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
        )

    response_body = b""
    async for item in response.body_iterator:
        response_body += item

    return Response(
        content=response_body,
        status_code=response.status_code,
        headers=dict(response.headers),
        media_type=response.media_type,
        background=BackgroundTask(self.log, request_body, response_body, details)
    )

But the problem does not solve. I still get time out.

Emad Helmi
  • 652
  • 8
  • 25

0 Answers0