feat: add 10min function-level cache to fetch_metar with stale fallback on error

This commit is contained in:
2569718930@qq.com
2026-03-11 04:23:13 +08:00
parent cc1a9a3b77
commit 4b51e0dd15
+22 -2
View File
@@ -80,10 +80,15 @@ class WeatherDataCollector:
self._ensemble_cache_lock = threading.Lock()
self._multi_model_cache_lock = threading.Lock()
self.meteoblue_cache_ttl_sec = int(
os.getenv("METEOBLUE_CACHE_TTL_SEC", "1800")
os.getenv("METEOBLUE_CACHE_TTL_SEC", "7200")
)
self._meteoblue_cache: Dict[str, Dict] = {}
self._meteoblue_cache_lock = threading.Lock()
self.metar_cache_ttl_sec = int(
os.getenv("METAR_CACHE_TTL_SEC", "600") # 默认 10 分钟
)
self._metar_cache: Dict[str, Dict] = {}
self._metar_cache_lock = threading.Lock()
# 设置代理
proxy = config.get("proxy")
@@ -267,6 +272,14 @@ class WeatherDataCollector:
logger.warning(f"未找到城市 {city} 对应的 ICAO 代码")
return None
cache_key = f"{icao}:{utc_offset}:{use_fahrenheit}"
now_ts = time.time()
with self._metar_cache_lock:
cached = self._metar_cache.get(cache_key)
if cached and now_ts - cached["t"] < self.metar_cache_ttl_sec:
logger.debug(f"METAR cache hit {icao} age={int(now_ts - cached['t'])}s")
return cached["d"]
try:
# NOAA Aviation Weather API (免费,无需 Key)
url = "https://aviationweather.gov/api/data/metar"
@@ -288,6 +301,7 @@ class WeatherDataCollector:
if not data:
return None
# 1. 取最新的观测作为当前状态
latest = data[0]
temp_c = latest.get("temp")
@@ -457,11 +471,17 @@ class WeatherDataCollector:
f"✈️ METAR {icao}: {temp:.1f}°{'F' if use_fahrenheit else 'C'} "
f"(obs: {obs_time})"
)
with self._metar_cache_lock:
self._metar_cache[cache_key] = {"d": result, "t": now_ts}
return result
except requests.exceptions.RequestException as e:
logger.error(f"METAR 请求失败 ({icao}): {e}")
with self._metar_cache_lock:
stale = self._metar_cache.get(cache_key)
if stale:
logger.warning(f"METAR {icao} 请求失败,使用缓存回退")
return stale["d"]
return None
except (KeyError, IndexError, TypeError) as e:
logger.error(f"METAR 数据解析失败 ({icao}): {e}")