fix: verify raw freshness by received time

This commit is contained in:
lingniu
2026-07-02 09:16:45 +08:00
parent 0a024f9a76
commit 318486b1e9
4 changed files with 130 additions and 20 deletions

View File

@@ -40,6 +40,14 @@ class Check:
message: str
@dataclass(frozen=True)
class CheckWindow:
date_from: str
date_to: str
stat_date: str
max_raw_age_minutes: float | None
def shanghai_day_window(now: dt.datetime | None = None) -> tuple[str, str]:
now = now or dt.datetime.now(tz=SHANGHAI)
local = now.astimezone(SHANGHAI)
@@ -48,6 +56,23 @@ def shanghai_day_window(now: dt.datetime | None = None) -> tuple[str, str]:
return start.isoformat(timespec="seconds"), end.isoformat(timespec="seconds")
def resolve_check_window(
raw_date: str | None,
max_raw_age_minutes: float,
now: dt.datetime | None = None,
) -> CheckWindow:
current = (now or dt.datetime.now(tz=SHANGHAI)).astimezone(SHANGHAI)
today = current.date()
if raw_date:
day = dt.date.fromisoformat(raw_date)
start = dt.datetime(day.year, day.month, day.day, tzinfo=SHANGHAI)
date_from, date_to = shanghai_day_window(start)
freshness = max_raw_age_minutes if day == today else None
return CheckWindow(date_from, date_to, raw_date, freshness)
date_from, date_to = shanghai_day_window(current)
return CheckWindow(date_from, date_to, date_from[:10], max_raw_age_minutes)
def api_url(base_url: str, path: str, params: dict[str, Any]) -> str:
url = base_url.rstrip("/") + path
if not params:
@@ -129,12 +154,15 @@ def parse_tdengine_utc_timestamp(value: str) -> dt.datetime:
def latest_age_minutes(items: list[Any], now: dt.datetime | None = None) -> float | None:
if not items or not isinstance(items[0], dict) or not items[0].get("ts"):
if not items or not isinstance(items[0], dict):
return None
timestamp = items[0].get("received_at") or items[0].get("ts")
if not timestamp:
return None
current = now or dt.datetime.now(tz=dt.timezone.utc)
if current.tzinfo is None:
current = current.replace(tzinfo=dt.timezone.utc)
latest = parse_tdengine_utc_timestamp(str(items[0]["ts"]))
latest = parse_tdengine_utc_timestamp(str(timestamp))
return max(0.0, (current.astimezone(dt.timezone.utc) - latest).total_seconds() / 60)
@@ -291,7 +319,7 @@ def build_check_specs(
min_stat: int,
max_raw_age_minutes: float | None = None,
) -> list[CheckSpec]:
raw_params = {"dateFrom": date_from, "dateTo": date_to, "limit": 1}
raw_params = {"dateFrom": date_from, "dateTo": date_to, "limit": 1, "orderBy": "receivedAt"}
gb32960_history_params = {"protocol": "GB32960", "dateFrom": date_from, "dateTo": date_to, "limit": 1}
jt808_history_params = {"protocol": "JT808", "dateFrom": date_from, "dateTo": date_to, "limit": 1}
yutong_mqtt_history_params = {"protocol": "YUTONG_MQTT", "dateFrom": date_from, "dateTo": date_to, "limit": 1}
@@ -489,24 +517,15 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
def main(argv: list[str]) -> int:
args = parse_args(argv)
if args.date:
day = dt.date.fromisoformat(args.date)
start = dt.datetime(day.year, day.month, day.day, tzinfo=SHANGHAI)
date_from, date_to = shanghai_day_window(start)
stat_date = args.date
max_raw_age_minutes = None
else:
date_from, date_to = shanghai_day_window()
stat_date = date_from[:10]
max_raw_age_minutes = args.max_raw_age_minutes
window = resolve_check_window(args.date, args.max_raw_age_minutes)
specs = build_check_specs(
date_from=date_from,
date_to=date_to,
stat_date=stat_date,
date_from=window.date_from,
date_to=window.date_to,
stat_date=window.stat_date,
min_raw=args.min_raw,
min_history=args.min_history,
min_stat=args.min_stat,
max_raw_age_minutes=max_raw_age_minutes,
max_raw_age_minutes=window.max_raw_age_minutes,
)
checks, payloads = query_payloads(args.base_url, specs, args.timeout)
checks.extend(run_checks(args.base_url, build_realtime_specs(payloads), args.timeout))
@@ -514,8 +533,8 @@ def main(argv: list[str]) -> int:
print(json.dumps({
"status": status,
"baseUrl": args.base_url,
"dateFrom": date_from,
"dateTo": date_to,
"dateFrom": window.date_from,
"dateTo": window.date_to,
"checks": [asdict(check) for check in checks],
}, ensure_ascii=False, indent=2))
return 0 if status == "pass" else 1