Stabilize METAR fetching with fallback requests
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
@@ -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}")
|
||||||
|
|||||||
Reference in New Issue
Block a user