我发现了一个有趣的行为。对于应用程序,我编写了一个自定义中间件来处理客户端,它没有等待响应并断开连接
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“寿命”协议似乎不受支持。
在本地,应用程序工作正常,但是一旦它被组装并发送到寄存器,然后在 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
如果您继承
__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 上阅读它。