Stabilize METAR fetching with fallback requests

This commit is contained in:
2569718930@qq.com
2026-04-16 15:43:47 +08:00
parent 25424700ce
commit 0eee5c8948
2 changed files with 47 additions and 12 deletions
+36 -12
View File
@@ -44,16 +44,40 @@ class MetarSourceMixin:
try: try:
url = "https://aviationweather.gov/api/data/metar" url = "https://aviationweather.gov/api/data/metar"
params = { history_hours = 24
"ids": icao,
"format": "json", def _request_metar_records(hours: int, timeout: float) -> list:
"hours": 24, response = self._http_get(
"_t": int(time.time()), url,
} params={
response = self.session.get(url, params=params, timeout=self.timeout) "ids": icao,
response.raise_for_status() "format": "json",
"hours": hours,
},
timeout=timeout,
)
response.raise_for_status()
payload = response.json()
return payload if isinstance(payload, list) else []
try:
data = _request_metar_records(
history_hours,
getattr(self, "metar_timeout_sec", self.timeout),
)
except httpx.HTTPError as primary_exc:
history_hours = 2
logger.warning(
f"METAR {icao} 24h 请求失败,尝试 latest fallback: {primary_exc}"
)
try:
data = _request_metar_records(
history_hours,
getattr(self, "metar_latest_timeout_sec", 2.5),
)
except httpx.HTTPError:
raise primary_exc
data = response.json()
if not data: if not data:
return None return None
@@ -63,7 +87,7 @@ class MetarSourceMixin:
def _parse_rawob_time(obs): def _parse_rawob_time(obs):
raw = obs.get("rawOb", "") raw = obs.get("rawOb", "")
match = re.search(r"(\d{2})(\d{2})(\d{2})Z", raw) match = re.search(r"\b(\d{2})(\d{2})(\d{2})Z\b", raw)
if match: if match:
_day, hour, minute = ( _day, hour, minute = (
int(match.group(1)), int(match.group(1)),
@@ -199,6 +223,7 @@ class MetarSourceMixin:
"today_obs": today_obs, "today_obs": today_obs,
"recent_obs": recent_obs_raw, "recent_obs": recent_obs_raw,
"unit": unit, "unit": unit,
"history_hours": history_hours,
} }
logger.info( logger.info(
@@ -246,9 +271,8 @@ class MetarSourceMixin:
"ids": icao, "ids": icao,
"format": "json", "format": "json",
"hours": 24, "hours": 24,
"_t": int(time.time()),
} }
response = self.session.get( response = self._http_get(
url, url,
params=params, params=params,
timeout=getattr(self, "metar_timeout_sec", self.timeout), timeout=getattr(self, "metar_timeout_sec", self.timeout),
+11
View File
@@ -130,12 +130,22 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
self.metar_timeout_sec = max( self.metar_timeout_sec = max(
2.0, float(os.getenv("POLYWEATHER_METAR_TIMEOUT_SEC", "4")) 2.0, float(os.getenv("POLYWEATHER_METAR_TIMEOUT_SEC", "4"))
) )
self.metar_latest_timeout_sec = max(
1.0, float(os.getenv("POLYWEATHER_METAR_LATEST_TIMEOUT_SEC", "2.5"))
)
self.metar_cluster_timeout_sec = max( self.metar_cluster_timeout_sec = max(
2.0, float(os.getenv("POLYWEATHER_METAR_CLUSTER_TIMEOUT_SEC", "3.5")) 2.0, float(os.getenv("POLYWEATHER_METAR_CLUSTER_TIMEOUT_SEC", "3.5"))
) )
self.user_agent = str(
os.getenv(
"POLYWEATHER_USER_AGENT",
"PolyWeather/1.0 (+https://polyweather-pro.vercel.app)",
)
).strip()
self.session = httpx.Client( self.session = httpx.Client(
timeout=self.timeout, timeout=self.timeout,
follow_redirects=True, follow_redirects=True,
headers={"User-Agent": self.user_agent},
limits=httpx.Limits(max_connections=50, max_keepalive_connections=20), limits=httpx.Limits(max_connections=50, max_keepalive_connections=20),
) )
self.open_meteo_cache_ttl_sec = int( self.open_meteo_cache_ttl_sec = int(
@@ -235,6 +245,7 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
timeout=self.timeout, timeout=self.timeout,
follow_redirects=True, follow_redirects=True,
proxy=proxy, proxy=proxy,
headers={"User-Agent": self.user_agent},
limits=httpx.Limits(max_connections=50, max_keepalive_connections=20), limits=httpx.Limits(max_connections=50, max_keepalive_connections=20),
) )
logger.info(f"正在使用天气数据代理: {proxy}") logger.info(f"正在使用天气数据代理: {proxy}")