当我使用自定义中间件时,ASGI 寿命出现问题

问题描述 投票:0回答:1

我发现了一个有趣的行为。对于应用程序,我编写了一个自定义中间件来处理客户端,它没有等待响应并断开连接

class NoResponseReturnMiddleware(BaseHTTPMiddleware):
    _ERROR_MESSAGE: str = "No response returned."

    def __init__(self, app: ASGIApp, logger: Logger):
        super().__init__(app)
        self.logger = logger

    async def __call__(self, scope, receive, send) -> None:
        request = Request(scope, receive, send)
        try:
            await super().__call__(scope, receive, send)
        except RuntimeError as exc:
            if await request.is_disconnected() and str(exc) == self._ERROR_MESSAGE:
                self.logger.debug(
                    "Remote client disconnected",
                    extra={
                        "url": request.url,
                        "method": request.method,
                        "path": request.url.path,
                        "query": request.url.query,
                    },
                )
            else:
                raise exc

    async def dispatch(self, request, call_next):
        return await call_next(request)

但是当我启动应用程序时,它会上升,尽管我收到一条消息:

ASGI“寿命”协议似乎不受支持。

enter image description here

在本地,应用程序工作正常,但是一旦它被组装并发送到寄存器,然后在 kubernetes 部署中使用,它的行为就会很奇怪,然后完全“死掉”(进入永久重启)。出现错误

Warning Unhealthy 5m5s (x3 over 5m25s)  kubelet      Liveness probe failed: Get "http://11.11.11.11.1:8000/": dial tcp 11.11.11.11.1:8000: connect: connection refused

这可能有某种关联吗?我读到这可能会导致服务器崩溃

更新:

尝试一下

uvicorn main:app --reload --lifespan on

你会得到一个错误:

assert scope["type"] in ("http", "websocket") AssertionError

修复它:

    async def __call__(self, scope, receive, send) -> None:
        if scope["type"] in ["http", "websocket"]:
            request = Request(scope, receive, send)
            ...
        return
fastapi uvicorn asgi
1个回答
2
投票

如果您继承

__call__
,则不应实现
BaseHTTPMiddleware
方法。使用它时,您应该只实现
dispatch
方法,如文档中所述:https://www.starlette.io/middleware/#basehttpmiddleware.

ASGI 以块的方式工作。每个中间件(或应用程序)调用下一个中间件(或应用程序),这些中间件(或应用程序)的类型是“websocket”、“http”或“lifespan”。

如果您创建的中间件用于“http”,那么您应该回退到下一个中间件,请参阅:

if scope["type"] != "http":
    return await self.app(scope, send, receive)
# Your middleware code should be here!

我们更新了 Starlette 文档,以提供有关 ASGI 中间件的更多信息。它将部署在下一个 Starlette 版本中,但您已经可以在 https://github.com/encode/starlette/blob/master/docs/middleware.md#pure-asgi-middleware 上阅读它。

© www.soinside.com 2019 - 2024. All rights reserved.