From d0ebdd60c0643b2332c5c6b1c96ddc8c9d9660b2 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 23 Aug 2026 02:02:31 +0800 Subject: [PATCH] refactor: route cache settings through runtime --- app/adapters/cache/backends.py | 19 ++++++---- app/adapters/cache/redis.py | 35 ++++++++++++------- .../backend-architecture-next-stage.md | 4 ++- .../configuration-debt-baseline.json | 4 +-- .../architecture/dependency-baseline.json | 6 ++-- 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/app/adapters/cache/backends.py b/app/adapters/cache/backends.py index 00780106c..bcd7049a2 100644 --- a/app/adapters/cache/backends.py +++ b/app/adapters/cache/backends.py @@ -14,7 +14,12 @@ from app.runtime.cache import ( DEFAULT_CACHE_REGION, configure_cache_factories, ) -from app.runtime.config import settings +from app.runtime import config as _runtime_config +from app.runtime.settings import get_runtime_setting + + +# 兼容旧插件对模块级 Settings 的覆盖,工厂实际读取统一经过 runtime 端口。 +settings = _runtime_config.settings class RedisBackend(CacheBackend): @@ -330,12 +335,14 @@ class AsyncFileBackend(AsyncCacheBackend): def configure_platform_cache() -> None: """把配置感知的 Redis 与文件适配器注册到平台缓存工厂。""" configure_cache_factories( - backend_type_provider=lambda: settings.CACHE_BACKEND_TYPE, + backend_type_provider=lambda: get_runtime_setting("CACHE_BACKEND_TYPE"), redis_factory=lambda ttl: RedisBackend(ttl=ttl), async_redis_factory=lambda ttl: AsyncRedisBackend(ttl=ttl), - file_factory=lambda base: FileBackend(base=base or settings.TEMP_PATH), - async_file_factory=lambda base: AsyncFileBackend( - base=base or settings.TEMP_PATH + file_factory=lambda base: FileBackend( + base=base or get_runtime_setting("TEMP_PATH") ), - file_ttl_provider=lambda: settings.TEMP_FILE_DAYS * 24 * 3600, + async_file_factory=lambda base: AsyncFileBackend( + base=base or get_runtime_setting("TEMP_PATH") + ), + file_ttl_provider=lambda: get_runtime_setting("TEMP_FILE_DAYS") * 24 * 3600, ) diff --git a/app/adapters/cache/redis.py b/app/adapters/cache/redis.py index 908e762b7..26b1af63c 100644 --- a/app/adapters/cache/redis.py +++ b/app/adapters/cache/redis.py @@ -9,11 +9,16 @@ import redis from redis.asyncio import BlockingConnectionPool as AsyncBlockingConnectionPool from redis.asyncio import Redis -from app.runtime.config import settings +from app.runtime import config as _runtime_config from app.runtime.log import logger from app.runtime.reload import ConfigReloadMixin +from app.runtime.settings import get_runtime_setting from app.foundation.singleton import Singleton + +# 兼容旧插件和测试对模块级 Settings 的覆盖,Redis 连接逻辑统一读取 runtime 端口。 +settings = _runtime_config.settings + # 类型缓存集合,针对非容器简单类型 _complex_serializable_types = set() _simple_serializable_types = set() @@ -97,7 +102,7 @@ class RedisHelper(ConfigReloadMixin, metaclass=Singleton): """ 初始化Redis助手实例 """ - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") self.client = None self._connect_lock = threading.RLock() @@ -112,15 +117,15 @@ class RedisHelper(ConfigReloadMixin, metaclass=Singleton): with self._connect_lock: if self.client is not None: return - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") connection_pool = redis.BlockingConnectionPool.from_url( self.redis_url, decode_responses=False, socket_timeout=_socket_timeout, socket_connect_timeout=_socket_connect_timeout, health_check_interval=_health_check_interval, - max_connections=settings.CACHE_REDIS_MAX_CONNECTIONS, - timeout=settings.CACHE_REDIS_POOL_TIMEOUT, + max_connections=get_runtime_setting("CACHE_REDIS_MAX_CONNECTIONS"), + timeout=get_runtime_setting("CACHE_REDIS_POOL_TIMEOUT"), ) client = redis.Redis(connection_pool=connection_pool) # 测试连接,确保Redis可用 @@ -138,7 +143,7 @@ class RedisHelper(ConfigReloadMixin, metaclass=Singleton): def on_config_changed(self): """缓存配置变化后重建同步 Redis 连接。""" with self._connect_lock: - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") self.close() self._connect() @@ -154,7 +159,9 @@ class RedisHelper(ConfigReloadMixin, metaclass=Singleton): """ try: # 如果有显式值,则直接使用,为0时说明不限制,如果未配置,开启BIG_MEMORY_MODE时为"1024mb",未开启时为"256mb" - maxmemory = settings.CACHE_REDIS_MAXMEMORY or ("1024mb" if settings.BIG_MEMORY_MODE else "256mb") + maxmemory = get_runtime_setting("CACHE_REDIS_MAXMEMORY") or ( + "1024mb" if get_runtime_setting("BIG_MEMORY_MODE") else "256mb" + ) self.client.config_set("maxmemory", maxmemory) self.client.config_set("maxmemory-policy", policy) logger.debug(f"Redis maxmemory set to {maxmemory}, policy: {policy}") @@ -364,7 +371,7 @@ class AsyncRedisHelper(ConfigReloadMixin, metaclass=Singleton): """ 初始化异步Redis助手实例 """ - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") self.client: Optional[Redis] = None self._loop: Optional[asyncio.AbstractEventLoop] = None self._connect_lock: Optional[asyncio.Lock] = None @@ -394,15 +401,15 @@ class AsyncRedisHelper(ConfigReloadMixin, metaclass=Singleton): await self._close_client() if self.client is not None: return - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") connection_pool = AsyncBlockingConnectionPool.from_url( self.redis_url, decode_responses=False, socket_timeout=_socket_timeout, socket_connect_timeout=_socket_connect_timeout, health_check_interval=_health_check_interval, - max_connections=settings.CACHE_REDIS_MAX_CONNECTIONS, - timeout=settings.CACHE_REDIS_POOL_TIMEOUT, + max_connections=get_runtime_setting("CACHE_REDIS_MAX_CONNECTIONS"), + timeout=get_runtime_setting("CACHE_REDIS_POOL_TIMEOUT"), ) client = Redis(connection_pool=connection_pool) self._loop = current_loop @@ -433,7 +440,7 @@ class AsyncRedisHelper(ConfigReloadMixin, metaclass=Singleton): async def on_config_changed(self): """缓存配置变化后异步重建 Redis 连接。""" - self.redis_url = settings.CACHE_BACKEND_URL + self.redis_url = get_runtime_setting("CACHE_BACKEND_URL") await self._close_client() await self._connect() @@ -449,7 +456,9 @@ class AsyncRedisHelper(ConfigReloadMixin, metaclass=Singleton): """ try: # 如果有显式值,则直接使用,为0时说明不限制,如果未配置,开启BIG_MEMORY_MODE时为"1024mb",未开启时为"256mb" - maxmemory = settings.CACHE_REDIS_MAXMEMORY or ("1024mb" if settings.BIG_MEMORY_MODE else "256mb") + maxmemory = get_runtime_setting("CACHE_REDIS_MAXMEMORY") or ( + "1024mb" if get_runtime_setting("BIG_MEMORY_MODE") else "256mb" + ) await self.client.config_set("maxmemory", maxmemory) await self.client.config_set("maxmemory-policy", policy) logger.debug(f"Redis maxmemory set to {maxmemory}, policy: {policy} (async)") diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index 8ba9ea59f..9de384e73 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -70,7 +70,7 @@ MoviePilot V3 当前不是“目录混乱、必须推倒重来”的状态。第 | legacy 默认模块契约 | 0 个宿主观察方法;未知动态方法保留 fallback | 所有静态宿主方法已有显式 V2 spec;真实 fallback 命中由 `module.contract.legacy_hit` 观测 | | 事件枚举 | 53 | 66 个静态 producer、15 个静态 consumer | | 专用 EventData model | 53 | Event Contract Registry 已为全部事件登记 typed payload/fallback 原因 | -| 直接读取 `settings` 的文件 | 109 | 仍按模块族迁移,动态协议和安全端口暂保留 | +| 直接读取 `settings` 的文件 | 107 | 仍按模块族迁移,动态协议和安全端口暂保留 | | `SystemConfigOper()` | 1 个 | 仅组合根创建 `SystemConfigService` 时保留 | | Model 上的 DB 查询装饰器 | 119 | `db_update`/`async_db_update` 为 0;查询 ABI 继续按 canonical 用例迁移 | | 路由端点 | 335 | 11 个已装饰端点超过 80 行,最大 400 行 | @@ -1029,6 +1029,8 @@ MFA/Passkey 专项测试与架构门禁通过,密钥类配置仍保留在安 随后将插件依赖扫描、插件包事务和 V3 资源安装适配器的部署配置读取迁移到同一 runtime 端口;资源适配器 保留模块级 `settings` 兼容入口供旧插件覆盖,实际逻辑动态读取 runtime 配置。插件/资源专项 141 项测试、 Pylint 与架构基线通过,配置债务由 112 个文件降至 109 个文件。 +缓存 Redis 连接池、内存限制和文件缓存工厂随后改用 runtime 配置端口,保留旧模块级 Settings 覆盖入口; +缓存专项 41 项测试与 Pylint 通过,配置债务由 109 个文件降至 107 个文件。 同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖 `app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI, diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 67bf7f133..5cdf84f5a 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,10 +9,8 @@ "root": "app" }, "settings_imports": { - "count": 109, + "count": 107, "files": [ - "app/adapters/cache/backends.py", - "app/adapters/cache/redis.py", "app/adapters/external/market.py", "app/adapters/external/server.py", "app/adapters/network/browser.py", diff --git a/tests/fixtures/architecture/dependency-baseline.json b/tests/fixtures/architecture/dependency-baseline.json index f36e14995..dd595ad5f 100644 --- a/tests/fixtures/architecture/dependency-baseline.json +++ b/tests/fixtures/architecture/dependency-baseline.json @@ -13,8 +13,8 @@ "runtime_to_db": [], "workflow_to_db": [] }, - "edge_count": 6419, - "edge_sha256": "dffb0fbffbe79a933346a0d5be5332b61ca2323f732ca1b9c919af8e01abe73e", + "edge_count": 6421, + "edge_sha256": "694818834db43d9b556226bb11ddfc5420d2475f03e83125b64b7bd41e4a0771", "edges": [ "app -> app.runtime", "app -> app.runtime.compat", @@ -25,12 +25,14 @@ "app.adapters.cache.backends -> app.runtime", "app.adapters.cache.backends -> app.runtime.cache", "app.adapters.cache.backends -> app.runtime.config", + "app.adapters.cache.backends -> app.runtime.settings", "app.adapters.cache.redis -> app.foundation", "app.adapters.cache.redis -> app.foundation.singleton", "app.adapters.cache.redis -> app.runtime", "app.adapters.cache.redis -> app.runtime.config", "app.adapters.cache.redis -> app.runtime.log", "app.adapters.cache.redis -> app.runtime.reload", + "app.adapters.cache.redis -> app.runtime.settings", "app.adapters.external.cookiecloud -> app.adapters", "app.adapters.external.cookiecloud -> app.adapters.network", "app.adapters.external.cookiecloud -> app.adapters.network.http",