refactor(tmdb): 空结果缓存过期时间收敛为设置项 EMPTY_RESULT_CACHE_TTL

- ConfigModel TMDB 配置区新增 EMPTY_RESULT_CACHE_TTL(默认 30 分钟),支持环境变量覆盖
- request/async_request/discover/TmdbCache 统一改读 settings,移除模块级常量与跨模块导入
This commit is contained in:
jxxghp
2026-08-16 21:20:32 +08:00
parent 2aca9cc06b
commit 1402626a4a
6 changed files with 20 additions and 24 deletions
+1 -2
View File
@@ -11,7 +11,6 @@ from app.domain.meta.metabase import MetaBase
from app.runtime.log import logger
from app.schemas.types import MediaSource, MediaType
from app.foundation.singleton import WeakSingleton
from app.modules.themoviedb.tmdbv3api.tmdb import EMPTY_RESULT_CACHE_TTL
lock = RLock()
PERSISTENCE_VERSION = 1
@@ -262,7 +261,7 @@ class TmdbCache(metaclass=WeakSingleton):
# 负识别缓存使用独立的短 TTL:故障期间「合法 JSON 但结果为空」会被
# 记为未识别,若按完整有效期固化,故障自愈后同名仍会被判无法识别;
# 短过期让恢复后可重新识别,真不存在的条目过期后重新确认一次即可
self._set(key, {"id": 0}, ttl=EMPTY_RESULT_CACHE_TTL)
self._set(key, {"id": 0}, ttl=settings.EMPTY_RESULT_CACHE_TTL)
def save(self, force: bool = False) -> None:
"""
@@ -1,5 +1,6 @@
from app.runtime.cache import cached
from ..tmdb import TMDb, EMPTY_RESULT_CACHE_TTL
from app.runtime.config import settings
from ..tmdb import TMDb
try:
from urllib import urlencode
@@ -13,7 +14,7 @@ class Discover(TMDb):
"tv": "/discover/tv"
}
@cached(maxsize=1, ttl=43200, empty_ttl=EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
def discover_movies(self, params_tuple):
"""
Discover movies by different types of data like average rating, number of votes, genres and certifications.
@@ -23,7 +24,7 @@ class Discover(TMDb):
params = dict(params_tuple)
return self._request_obj(self._urls["movies"], urlencode(params), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
def discover_tv_shows(self, params_tuple):
"""
Discover TV shows by different types of data like average rating, number of votes, genres,
@@ -33,7 +34,7 @@ class Discover(TMDb):
"""
return self._request_obj(self._urls["tv"], urlencode(params_tuple), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
async def async_discover_movies(self, params_tuple):
"""
Discover movies by different types of data like average rating, number of votes, genres and certifications.(异步版本)
@@ -43,7 +44,7 @@ class Discover(TMDb):
params = dict(params_tuple)
return await self._async_request_obj(self._urls["movies"], urlencode(params), key="results", call_cached=False)
@cached(maxsize=1, ttl=43200, empty_ttl=EMPTY_RESULT_CACHE_TTL)
@cached(maxsize=1, ttl=43200, empty_ttl=settings.EMPTY_RESULT_CACHE_TTL)
async def async_discover_tv_shows(self, params_tuple):
"""
Discover TV shows by different types of data like average rating, number of votes, genres,
+4 -9
View File
@@ -22,11 +22,6 @@ logger = logging.getLogger(__name__)
# 故取区间内的经验值。
RETRY_BACKOFF_SECONDS = 2
# 空结果缓存的独立过期时间(秒)。TMDB 代理故障期间「合法 JSON 但 results 为空」的
# 响应会随默认 TTL(可达数十小时)固化,故障自愈后同 key 仍持续命中空结果;空结果
# 改用 30 分钟短 TTL,既能拦住故障窗口内的重复回源,又能在故障恢复后较快自然失效。
EMPTY_RESULT_CACHE_TTL = 30 * 60
def _is_business_failure_snapshot(snapshot) -> bool:
"""
@@ -47,8 +42,8 @@ def _is_empty_result_snapshot(snapshot) -> bool:
判断响应快照是否为空结果(列表/搜索类接口的 results 为空列表)。
这类快照结构合法但无业务内容,常由代理瞬时故障产生;不能靠 skip_none/skip_empty
识别(快照本身是非空字典),需单独谓词判定后按 EMPTY_RESULT_CACHE_TTL 短 TTL
缓存。详情类接口无 results 字段,不属于空结果。
识别(快照本身是非空字典),需单独谓词判定后按 settings.EMPTY_RESULT_CACHE_TTL
短 TTL 缓存。详情类接口无 results 字段,不属于空结果。
"""
if not isinstance(snapshot, dict):
return False
@@ -180,7 +175,7 @@ class TMDb(object):
@cached(maxsize=settings.CONF.tmdb, ttl=settings.CONF.meta, skip_none=True,
skip_if=_is_business_failure_snapshot,
empty_ttl=EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
empty_ttl=settings.EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
def request(self, method, url, data, json, **kwargs):
req = self._request_once(method, url, data, json)
if req is None and method == "GET" and self._owns_session:
@@ -206,7 +201,7 @@ class TMDb(object):
@cached(maxsize=settings.CONF.tmdb, ttl=settings.CONF.meta, skip_none=True,
skip_if=_is_business_failure_snapshot,
empty_ttl=EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
empty_ttl=settings.EMPTY_RESULT_CACHE_TTL, empty_if=_is_empty_result_snapshot)
async def async_request(self, method, url, data, json, **kwargs):
req = await self._async_request_once(method, url, data, json)
if req is None: