mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
fix: 禁用httpx连接池并显式关闭响应防止连接泄漏
This commit is contained in:
@@ -60,6 +60,10 @@ class ManageApiClient:
|
|||||||
|
|
||||||
# 为每个事件循环创建独立的客户端
|
# 为每个事件循环创建独立的客户端
|
||||||
if loop_id not in cls._async_clients:
|
if loop_id not in cls._async_clients:
|
||||||
|
# 服务端可能主动关闭连接,httpx 连接池无法正确检测和清理
|
||||||
|
limits = httpx.Limits(
|
||||||
|
max_keepalive_connections=0, # 禁用 keep-alive,每次都新建连接
|
||||||
|
)
|
||||||
cls._async_clients[loop_id] = httpx.AsyncClient(
|
cls._async_clients[loop_id] = httpx.AsyncClient(
|
||||||
base_url=cls.config.get("url"),
|
base_url=cls.config.get("url"),
|
||||||
headers={
|
headers={
|
||||||
@@ -68,6 +72,7 @@ class ManageApiClient:
|
|||||||
"Authorization": "Bearer " + cls._secret,
|
"Authorization": "Bearer " + cls._secret,
|
||||||
},
|
},
|
||||||
timeout=cls.config.get("timeout", 30),
|
timeout=cls.config.get("timeout", 30),
|
||||||
|
limits=limits, # 使用限制
|
||||||
)
|
)
|
||||||
return cls._async_clients[loop_id]
|
return cls._async_clients[loop_id]
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
@@ -80,21 +85,27 @@ class ManageApiClient:
|
|||||||
# 确保客户端已创建
|
# 确保客户端已创建
|
||||||
client = await cls._ensure_async_client()
|
client = await cls._ensure_async_client()
|
||||||
endpoint = endpoint.lstrip("/")
|
endpoint = endpoint.lstrip("/")
|
||||||
response = await client.request(method, endpoint, **kwargs)
|
response = None
|
||||||
response.raise_for_status()
|
try:
|
||||||
|
response = await client.request(method, endpoint, **kwargs)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
result = response.json()
|
result = response.json()
|
||||||
|
|
||||||
# 处理API返回的业务错误
|
# 处理API返回的业务错误
|
||||||
if result.get("code") == 10041:
|
if result.get("code") == 10041:
|
||||||
raise DeviceNotFoundException(result.get("msg"))
|
raise DeviceNotFoundException(result.get("msg"))
|
||||||
elif result.get("code") == 10042:
|
elif result.get("code") == 10042:
|
||||||
raise DeviceBindException(result.get("msg"))
|
raise DeviceBindException(result.get("msg"))
|
||||||
elif result.get("code") != 0:
|
elif result.get("code") != 0:
|
||||||
raise Exception(f"API返回错误: {result.get('msg', '未知错误')}")
|
raise Exception(f"API返回错误: {result.get('msg', '未知错误')}")
|
||||||
|
|
||||||
# 返回成功数据
|
# 返回成功数据
|
||||||
return result.get("data") if result.get("code") == 0 else None
|
return result.get("data") if result.get("code") == 0 else None
|
||||||
|
finally:
|
||||||
|
# 确保响应被关闭(即使异常也会执行)
|
||||||
|
if response is not None:
|
||||||
|
await response.aclose()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _should_retry(cls, exception: Exception) -> bool:
|
def _should_retry(cls, exception: Exception) -> bool:
|
||||||
|
|||||||
Reference in New Issue
Block a user