调整部分前端布局和后端增删改逻辑

This commit is contained in:
焦龙言
2026-09-20 10:38:10 +08:00
parent acddc8a237
commit 3edba99d2d
227 changed files with 122871 additions and 839 deletions
@@ -0,0 +1,3 @@
from .service import CACHE_RUNTIME, CacheRuntimeService
__all__ = ['CACHE_RUNTIME', 'CacheRuntimeService']
@@ -0,0 +1,41 @@
from importlib import import_module
from typing import Any
REDIS_TTL_KEY_NOT_FOUND = -2
REDIS_TTL_PERSISTENT = -1
class CacheInfrastructureGateway:
"""
缓存基础设施网关。
该对象负责延迟加载 Redis 相关基础设施依赖,
供缓存运行时 facade 和其协作对象统一复用。
"""
@staticmethod
def get_redis_error_class() -> type[Exception]:
"""
获取 Redis 异常类型。
:return: Redis 异常类型
"""
return import_module('redis.exceptions').RedisError
@staticmethod
def get_redis_init_key_config() -> Any:
"""
获取系统缓存初始化键枚举。
:return: 缓存初始化键枚举
"""
return import_module('common.enums').RedisInitKeyConfig
@staticmethod
def get_redis_util() -> Any:
"""
获取 Redis 工具类。
:return: Redis 工具类
"""
return import_module('config.get_redis').RedisUtil
@@ -0,0 +1,216 @@
from typing import Any
from cli.exit_codes import RUNTIME_ERROR
from .gateway import REDIS_TTL_KEY_NOT_FOUND, REDIS_TTL_PERSISTENT, CacheInfrastructureGateway
from .support import CacheDomainSupport, CacheRedisSupport
class CacheRuntimeService:
"""
缓存运行时服务。
该服务作为缓存运行时 facade,对外统一暴露缓存统计、键列表、键值、
TTL 读取,以及缓存清理和预热入口。
:param infrastructure_gateway: 缓存基础设施网关
:param domain_support: 缓存领域支持对象
:param redis_support: 缓存 Redis 访问支持对象
"""
def __init__(
self,
*,
infrastructure_gateway: CacheInfrastructureGateway | None = None,
domain_support: CacheDomainSupport | None = None,
redis_support: CacheRedisSupport | None = None,
) -> None:
"""
初始化缓存运行时服务。
:param infrastructure_gateway: 缓存基础设施网关
:param domain_support: 缓存领域支持对象
:param redis_support: 缓存 Redis 访问支持对象
:return: None
"""
self.infrastructure_gateway = infrastructure_gateway or CacheInfrastructureGateway()
self.domain_support = domain_support or CacheDomainSupport(self.infrastructure_gateway)
self.redis_support = redis_support or CacheRedisSupport(self.infrastructure_gateway, self.domain_support)
async def get_cache_stats(self) -> dict[str, Any]:
"""
获取缓存统计信息。
:return: 缓存统计结果
"""
redis_error = self.infrastructure_gateway.get_redis_error_class()
try:
async with self.redis_support.redis_session() as (redis, _redis_util):
info = await redis.info()
db_size = await redis.dbsize()
command_stats_dict = await redis.info('commandstats')
command_stats = [
{'name': key.split('_', 1)[1], 'value': int(value.get('calls', 0))}
for key, value in sorted(command_stats_dict.items(), key=lambda item: item[0])
]
return {
'ok': True,
'dbSize': db_size,
'commandStats': command_stats,
'cacheNames': self.domain_support.build_cache_name_items(),
'info': info,
}
except redis_error as exc:
return self.redis_support.build_redis_error_result('读取缓存统计失败', exc)
async def list_cache_keys(self, cache_name: str) -> dict[str, Any]:
"""
列出指定缓存名称下的键名。
:param cache_name: 缓存名称
:return: 缓存键名列表结果
"""
redis_error = self.infrastructure_gateway.get_redis_error_class()
try:
async with self.redis_support.redis_session() as (redis, _redis_util):
cache_keys: list[str] = await redis.keys(self.redis_support.build_cache_name_keys_pattern(cache_name))
key_items = self.domain_support.extract_cache_key_items(cache_name, cache_keys)
return {'ok': True, 'cacheName': cache_name, 'count': len(key_items), 'keys': key_items}
except redis_error as exc:
return self.redis_support.build_redis_error_result('读取缓存键名失败', exc)
async def get_cache_value(self, cache_name: str, cache_key: str) -> dict[str, Any]:
"""
读取指定缓存键值。
:param cache_name: 缓存名称
:param cache_key: 缓存键名
:return: 缓存值结果
"""
redis_error = self.infrastructure_gateway.get_redis_error_class()
full_cache_key = self.domain_support.build_full_cache_key(cache_name, cache_key)
try:
async with self.redis_support.redis_session() as (redis, _redis_util):
cache_value = await redis.get(full_cache_key)
if cache_value is None:
return self.domain_support.build_missing_cache_result(cache_name, cache_key)
return {
'ok': True,
'cacheName': cache_name,
'cacheKey': cache_key,
'fullCacheKey': full_cache_key,
'cacheValue': cache_value,
}
except redis_error as exc:
return self.redis_support.build_redis_error_result('读取缓存内容失败', exc)
async def get_cache_ttl(self, cache_name: str, cache_key: str) -> dict[str, Any]:
"""
读取指定缓存键的剩余过期时间。
:param cache_name: 缓存名称
:param cache_key: 缓存键名
:return: 缓存 TTL 结果
"""
redis_error = self.infrastructure_gateway.get_redis_error_class()
full_cache_key = self.domain_support.build_full_cache_key(cache_name, cache_key)
try:
async with self.redis_support.redis_session() as (redis, _redis_util):
ttl_seconds = await redis.ttl(full_cache_key)
if ttl_seconds == REDIS_TTL_KEY_NOT_FOUND:
return self.domain_support.build_missing_cache_result(cache_name, cache_key)
return {
'ok': True,
'message': '缓存剩余过期时间读取成功' if ttl_seconds >= 0 else '缓存存在且未设置过期时间',
'cacheName': cache_name,
'cacheKey': cache_key,
'fullCacheKey': full_cache_key,
'ttlSeconds': ttl_seconds,
'persistent': ttl_seconds == REDIS_TTL_PERSISTENT,
'expires': ttl_seconds >= 0,
}
except redis_error as exc:
return self.redis_support.build_redis_error_result('读取缓存剩余过期时间失败', exc)
async def clear_cache(
self,
*,
cache_name: str = '',
cache_key: str = '',
clear_all: bool = False,
dry_run: bool = False,
) -> dict[str, Any]:
"""
清理缓存。
:param cache_name: 需要按缓存名称清理的前缀
:param cache_key: 需要按缓存键名模糊清理的键
:param clear_all: 是否清理全部缓存
:param dry_run: 是否仅演练执行
:return: 缓存清理结果
"""
selected_modes = [bool(cache_name), bool(cache_key), clear_all]
if sum(selected_modes) != 1:
return {
'ok': False,
'message': '必须且只能指定一种清理方式:--cache-name、--cache-key 或 --all',
'exit_code': RUNTIME_ERROR,
}
redis_error = self.infrastructure_gateway.get_redis_error_class()
try:
async with self.redis_support.redis_session() as (redis, redis_util):
target_pattern = self.redis_support.build_clear_target_pattern(
cache_name=cache_name,
cache_key=cache_key,
clear_all=clear_all,
)
if target_pattern is None:
target_keys = sorted(await redis.keys())
else:
target_keys = sorted(await redis.keys(target_pattern))
result = {
'ok': True,
'dryRun': dry_run,
'matchedCount': len(target_keys),
'matchedKeys': target_keys,
'scope': self.domain_support.build_clear_scope(
cache_name=cache_name,
cache_key=cache_key,
clear_all=clear_all,
),
}
if dry_run:
result['message'] = '缓存清理演练完成,未执行实际删除'
return result
if target_keys:
await redis.delete(*target_keys)
if clear_all:
await redis_util.init_sys_dict(redis)
await redis_util.init_sys_config(redis)
result['message'] = '缓存清理完成'
return result
except redis_error as exc:
return self.redis_support.build_redis_error_result('清理缓存失败', exc)
async def warmup_cache(self) -> dict[str, Any]:
"""
预热系统缓存。
:return: 缓存预热执行结果
"""
redis_error = self.infrastructure_gateway.get_redis_error_class()
try:
async with self.redis_support.redis_session() as (redis, redis_util):
await redis_util.init_sys_dict(redis)
await redis_util.init_sys_config(redis)
return {'ok': True, 'message': '缓存预热完成'}
except redis_error as exc:
return self.redis_support.build_redis_error_result('缓存预热失败', exc)
CACHE_RUNTIME = CacheRuntimeService()
@@ -0,0 +1,201 @@
from contextlib import asynccontextmanager
from typing import Any
from cli.exit_codes import REDIS_ERROR, RUNTIME_ERROR
from .gateway import CacheInfrastructureGateway
class CacheDomainSupport:
"""
缓存领域支持对象。
该对象负责缓存名称列表构建、键范围解析和 TTL 结果判定等
局部缓存规则,避免主运行时服务继续承载细碎领域判断。
:param infrastructure_gateway: 缓存基础设施网关
"""
def __init__(self, infrastructure_gateway: CacheInfrastructureGateway) -> None:
"""
初始化缓存领域支持对象。
:param infrastructure_gateway: 缓存基础设施网关
:return: None
"""
self.infrastructure_gateway = infrastructure_gateway
def build_cache_name_items(self) -> list[dict[str, Any]]:
"""
构建系统内置缓存名称列表。
:return: 缓存名称列表
"""
redis_init_key_config = self.infrastructure_gateway.get_redis_init_key_config()
return [
{
'cacheName': key_config.key,
'remark': key_config.remark,
}
for key_config in redis_init_key_config
]
@staticmethod
def build_full_cache_key(cache_name: str, cache_key: str) -> str:
"""
构建缓存完整键名。
:param cache_name: 缓存名称
:param cache_key: 缓存键名
:return: 完整缓存键名
"""
return f'{cache_name}:{cache_key}'
def build_missing_cache_result(self, cache_name: str, cache_key: str) -> dict[str, Any]:
"""
构建缓存不存在的统一结果。
:param cache_name: 缓存名称
:param cache_key: 缓存键名
:return: 缓存不存在结果
"""
full_cache_key = self.build_full_cache_key(cache_name, cache_key)
return {
'ok': False,
'message': f'缓存不存在:{full_cache_key}',
'cacheName': cache_name,
'cacheKey': cache_key,
'fullCacheKey': full_cache_key,
'exit_code': RUNTIME_ERROR,
}
@staticmethod
def build_cache_name_pattern(cache_name: str) -> str:
"""
构建按缓存名称扫描时使用的 Redis 键模式。
:param cache_name: 缓存名称
:return: Redis 键匹配模式
"""
return f'{cache_name}:*'
@staticmethod
def extract_cache_key_items(cache_name: str, cache_keys: list[str]) -> list[str]:
"""
从缓存完整键名列表中提取相对键名。
:param cache_name: 缓存名称
:param cache_keys: 完整缓存键名列表
:return: 相对键名列表
"""
return [key.split(':', 1)[1] for key in sorted(cache_keys) if key.startswith(f'{cache_name}:')]
@staticmethod
def build_clear_scope(
*,
cache_name: str,
cache_key: str,
clear_all: bool,
) -> dict[str, str]:
"""
构建缓存清理范围定义。
:param cache_name: 缓存名称
:param cache_key: 缓存键名片段
:param clear_all: 是否清理全部缓存
:return: 清理范围定义
"""
if clear_all:
return {'mode': 'all'}
if cache_name:
return {'mode': 'cacheName', 'cacheName': cache_name}
return {'mode': 'cacheKey', 'cacheKey': cache_key}
class CacheRedisSupport:
"""
缓存 Redis 访问支持对象。
该对象负责 Redis 连接生命周期、错误结果规整和缓存键模式拼装,
避免主运行时服务继续承载基础设施桥接细节。
:param infrastructure_gateway: 缓存基础设施网关
:param domain_support: 缓存领域支持对象
"""
def __init__(
self,
infrastructure_gateway: CacheInfrastructureGateway,
domain_support: CacheDomainSupport,
) -> None:
"""
初始化缓存 Redis 访问支持对象。
:param infrastructure_gateway: 缓存基础设施网关
:param domain_support: 缓存领域支持对象
:return: None
"""
self.infrastructure_gateway = infrastructure_gateway
self.domain_support = domain_support
@asynccontextmanager
async def redis_session(self) -> Any:
"""
创建并托管 Redis 会话。
:return: `(redis, redis_util)` 元组
"""
redis = None
redis_util = self.infrastructure_gateway.get_redis_util()
try:
redis = await redis_util.create_redis_pool(log_enabled=False)
yield redis, redis_util
finally:
if redis is not None:
await redis.close()
@staticmethod
def build_redis_error_result(message: str, exc: Exception) -> dict[str, Any]:
"""
构建统一 Redis 异常结果。
:param message: 失败消息
:param exc: 原始异常
:return: 标准失败结果
"""
return {
'ok': False,
'message': message,
'error': str(exc),
'exit_code': REDIS_ERROR,
}
def build_cache_name_keys_pattern(self, cache_name: str) -> str:
"""
构建按缓存名称读取键列表时使用的模式。
:param cache_name: 缓存名称
:return: Redis 键匹配模式
"""
return self.domain_support.build_cache_name_pattern(cache_name)
def build_clear_target_pattern(
self,
*,
cache_name: str,
cache_key: str,
clear_all: bool,
) -> str | None:
"""
构建缓存清理目标的 Redis 键匹配模式。
:param cache_name: 缓存名称
:param cache_key: 缓存键名片段
:param clear_all: 是否清理全部缓存
:return: Redis 键匹配模式;全部清理时返回 `None`
"""
if clear_all:
return None
if cache_name:
return self.domain_support.build_cache_name_pattern(cache_name)
return f'*{cache_key}'