mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 00:32:06 +08:00
perf: optimize timeout handling for database and cache operations
This commit is contained in:
@@ -79,21 +79,37 @@ async def is_ban(user_id: str | None, group_id: str | None) -> int:
|
|||||||
ban_dao.safe_get_or_none(user_id=user_id, group_id__isnull=True)
|
ban_dao.safe_get_or_none(user_id=user_id, group_id__isnull=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
# 等待所有查询完成,添加超时控制
|
# 等待所有查询完成,添加超时控制(使用更短的超时时间,快速失败)
|
||||||
if tasks:
|
if tasks:
|
||||||
try:
|
try:
|
||||||
|
# 使用更短的超时时间(1.5秒),避免在高并发下等待太久
|
||||||
|
# 如果查询超时,视为未ban,允许继续执行
|
||||||
ban_records = await asyncio.wait_for(
|
ban_records = await asyncio.wait_for(
|
||||||
asyncio.gather(*tasks), timeout=DB_TIMEOUT_SECONDS
|
asyncio.gather(*tasks, return_exceptions=True),
|
||||||
|
timeout=min(DB_TIMEOUT_SECONDS, 1.5),
|
||||||
)
|
)
|
||||||
|
# 处理可能的异常
|
||||||
|
valid_records = []
|
||||||
|
for record in ban_records:
|
||||||
|
if isinstance(record, Exception):
|
||||||
|
logger.warning(
|
||||||
|
f"查询ban记录时出现异常: {record}",
|
||||||
|
LOGGER_COMMAND,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
valid_records.append(record)
|
||||||
|
|
||||||
if len(tasks) == 2:
|
if len(tasks) == 2:
|
||||||
group_user, user = ban_records
|
group_user = valid_records[0] if len(valid_records) > 0 else None
|
||||||
|
user = valid_records[1] if len(valid_records) > 1 else None
|
||||||
elif user_id and group_id:
|
elif user_id and group_id:
|
||||||
group_user = ban_records[0]
|
group_user = valid_records[0] if valid_records else None
|
||||||
else:
|
else:
|
||||||
user = ban_records[0]
|
user = valid_records[0] if valid_records else None
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
logger.error(
|
logger.warning(
|
||||||
f"查询ban记录超时: user_id={user_id}, group_id={group_id}",
|
f"查询ban记录超时(视为未ban): "
|
||||||
|
f"user_id={user_id}, group_id={group_id}",
|
||||||
LOGGER_COMMAND,
|
LOGGER_COMMAND,
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Vendored
+6
-5
@@ -599,8 +599,6 @@ class CacheManager:
|
|||||||
返回:
|
返回:
|
||||||
bool: 是否成功
|
bool: 是否成功
|
||||||
"""
|
"""
|
||||||
from zhenxun.services.db_context import DB_TIMEOUT_SECONDS
|
|
||||||
|
|
||||||
# 如果缓存被禁用或缓存模式为NONE,直接返回False
|
# 如果缓存被禁用或缓存模式为NONE,直接返回False
|
||||||
if not self.enabled or cache_config.cache_mode == CacheMode.NONE:
|
if not self.enabled or cache_config.cache_mode == CacheMode.NONE:
|
||||||
return False
|
return False
|
||||||
@@ -615,14 +613,17 @@ class CacheManager:
|
|||||||
# 设置过期时间
|
# 设置过期时间
|
||||||
ttl = expire if expire is not None else model.expire
|
ttl = expire if expire is not None else model.expire
|
||||||
|
|
||||||
# 设置缓存
|
# 设置缓存(使用较短的超时时间,避免阻塞主流程)
|
||||||
await asyncio.wait_for(
|
await asyncio.wait_for(
|
||||||
self.cache_backend.set(cache_key, serialized_value, ttl=ttl), # type: ignore
|
self.cache_backend.set(cache_key, serialized_value, ttl=ttl), # type: ignore
|
||||||
timeout=DB_TIMEOUT_SECONDS,
|
timeout=min(CACHE_TIMEOUT, 2.0), # 最多2秒,避免阻塞太久
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
logger.error(f"设置缓存 {cache_type}:{cache_key} 超时", LOG_COMMAND)
|
logger.warning(
|
||||||
|
f"设置缓存 {cache_type}:{cache_key} 超时(已跳过,不影响主流程)",
|
||||||
|
LOG_COMMAND,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"设置缓存 {cache_type} 失败", LOG_COMMAND, e=e)
|
logger.error(f"设置缓存 {cache_type} 失败", LOG_COMMAND, e=e)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
from typing import Any, ClassVar, Generic, TypeVar, cast
|
from typing import Any, ClassVar, Generic, TypeVar, cast
|
||||||
|
|
||||||
from zhenxun.services.cache import Cache, CacheRoot, cache_config
|
from zhenxun.services.cache import Cache, CacheRoot, cache_config
|
||||||
@@ -212,9 +213,13 @@ class DataAccess(Generic[T]):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.model_cls.__name__} 从缓存获取数据失败: {kwargs}", e=e)
|
logger.error(f"{self.model_cls.__name__} 从缓存获取数据失败: {kwargs}", e=e)
|
||||||
|
|
||||||
# 如果缓存中没有,从数据库获取
|
# 如果缓存中没有,从数据库获取(使用超时控制)
|
||||||
logger.debug(f"{self.model_cls.__name__} 从数据库获取数据: {kwargs}")
|
logger.debug(f"{self.model_cls.__name__} 从数据库获取数据: {kwargs}")
|
||||||
data = await db_query_func(*args, **kwargs)
|
data = await with_db_timeout(
|
||||||
|
db_query_func(*args, **kwargs),
|
||||||
|
operation=f"{self.model_cls.__name__}.{db_query_func.__name__}",
|
||||||
|
source="DataAccess._get_with_cache",
|
||||||
|
)
|
||||||
|
|
||||||
# 如果获取到数据,存入缓存
|
# 如果获取到数据,存入缓存
|
||||||
if data:
|
if data:
|
||||||
@@ -222,31 +227,48 @@ class DataAccess(Generic[T]):
|
|||||||
# 生成缓存键
|
# 生成缓存键
|
||||||
cache_key = self._build_cache_key_for_item(data)
|
cache_key = self._build_cache_key_for_item(data)
|
||||||
if cache_key is not None:
|
if cache_key is not None:
|
||||||
# 存入缓存
|
# 存入缓存(失败不影响主流程)
|
||||||
await self.cache.set(cache_key, data)
|
try:
|
||||||
self._cache_stats[self.cache_type]["sets"] += 1
|
# 使用较短的超时时间,避免阻塞
|
||||||
logger.debug(
|
await asyncio.wait_for(
|
||||||
f"{self.model_cls.__name__} 数据已存入缓存: {cache_key}"
|
self.cache.set(cache_key, data), timeout=1.0
|
||||||
)
|
)
|
||||||
|
self._cache_stats[self.cache_type]["sets"] += 1
|
||||||
|
logger.debug(
|
||||||
|
f"{self.model_cls.__name__} 数据已存入缓存: {cache_key}"
|
||||||
|
)
|
||||||
|
except (asyncio.TimeoutError, Exception) as cache_err:
|
||||||
|
# 缓存设置失败不影响数据返回,只记录警告
|
||||||
|
logger.warning(
|
||||||
|
f"{self.model_cls.__name__} 存入缓存失败(超时或异常),"
|
||||||
|
f"参数: {kwargs}",
|
||||||
|
e=cache_err,
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{self.model_cls.__name__} 存入缓存失败,参数: {kwargs}", e=e
|
f"{self.model_cls.__name__} 存入缓存失败,参数: {kwargs}", e=e
|
||||||
)
|
)
|
||||||
elif cache_key is not None:
|
elif cache_key is not None:
|
||||||
# 如果没有获取到数据,缓存空结果
|
# 如果没有获取到数据,缓存空结果(失败不影响主流程)
|
||||||
try:
|
try:
|
||||||
# 存入空结果缓存,使用较短的过期时间
|
# 存入空结果缓存,使用较短的过期时间和超时时间
|
||||||
await self.cache.set(
|
await asyncio.wait_for(
|
||||||
cache_key, self._NULL_RESULT, expire=self._NULL_RESULT_TTL
|
self.cache.set(
|
||||||
|
cache_key, self._NULL_RESULT, expire=self._NULL_RESULT_TTL
|
||||||
|
),
|
||||||
|
timeout=1.0,
|
||||||
)
|
)
|
||||||
self._cache_stats[self.cache_type]["null_sets"] += 1
|
self._cache_stats[self.cache_type]["null_sets"] += 1
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.model_cls.__name__} 空结果已存入缓存: {cache_key},"
|
f"{self.model_cls.__name__} 空结果已存入缓存: {cache_key},"
|
||||||
f" TTL={self._NULL_RESULT_TTL}秒"
|
f" TTL={self._NULL_RESULT_TTL}秒"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except (asyncio.TimeoutError, Exception) as cache_err:
|
||||||
logger.error(
|
# 空结果缓存设置失败不影响数据返回,只记录警告
|
||||||
f"{self.model_cls.__name__} 存入空结果缓存失败,参数: {kwargs}", e=e
|
logger.warning(
|
||||||
|
f"{self.model_cls.__name__} 存入空结果缓存失败(超时或异常),"
|
||||||
|
f"参数: {kwargs}",
|
||||||
|
e=cache_err,
|
||||||
)
|
)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|||||||
Reference in New Issue
Block a user