refactor: route cache settings through runtime

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