Files
FishServer/scripts/biomass_poller.py
2026-04-08 21:05:45 +08:00

110 lines
3.2 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
独立进程:轮询 Fish API 的两个结果接口,用 loguru 输出响应。
BIOMASS_API_BASE=http://127.0.0.1:8000 POLL_INTERVAL=5 \\
python scripts/biomass_poller.py
依赖(与 fish_api dev 组一致httpx、loguru
cd fish_api && pip install -e ".[dev]"
"""
from __future__ import annotations
import argparse
import asyncio
import json
import os
import sys
from typing import Any
import httpx
from loguru import logger
def _fmt_body(resp: httpx.Response) -> Any:
try:
return resp.json()
except Exception:
return resp.text
_last_camera: dict | None = None
_last_health: dict | None = None
def _has_data(body: Any) -> bool:
"""非空业务数据code==200 且 data 里至少有一个非空字段。"""
if not isinstance(body, dict):
return False
if body.get("code") != 200:
return True # 错误也算"新信息"
data = body.get("data", {})
if not isinstance(data, dict):
return bool(data)
return any(bool(v) for v in data.values())
async def poll_once(client: httpx.AsyncClient, base: str) -> None:
global _last_camera, _last_health
base = base.rstrip("/")
camera_url = f"{base}/api/v1/biomass/real/camera/"
health_url = f"{base}/api/v1/biomass/health/result/"
r1 = await client.get(camera_url)
r2 = await client.get(health_url)
b1 = _fmt_body(r1)
b2 = _fmt_body(r2)
changed1 = b1 != _last_camera
changed2 = b2 != _last_health
if changed1 and _has_data(b1):
logger.info("[real/camera/] HTTP {} | {}", r1.status_code, json.dumps(b1, ensure_ascii=False))
if changed2 and _has_data(b2):
logger.info("[health/result/] HTTP {} | {}", r2.status_code, json.dumps(b2, ensure_ascii=False))
_last_camera = b1
_last_health = b2
async def poll_loop(base: str, interval: float) -> None:
async with httpx.AsyncClient(timeout=30.0) as client:
while True:
try:
await poll_once(client, base)
except Exception:
logger.exception("poll round failed")
await asyncio.sleep(max(interval, 0.5))
def main() -> None:
parser = argparse.ArgumentParser(description="Poll Fish API biomass GET endpoints.")
parser.add_argument(
"--base-url",
default=os.environ.get("BIOMASS_API_BASE", "http://127.0.0.1:8000"),
help="Fish API 根 URL默认 BIOMASS_API_BASE 或 http://127.0.0.1:8000",
)
parser.add_argument(
"--interval",
type=float,
default=float(os.environ.get("POLL_INTERVAL", "5")),
help="轮询间隔秒数(默认 POLL_INTERVAL 或 5",
)
args = parser.parse_args()
logger.remove()
logger.add(
sys.stderr,
level=os.environ.get("LOG_LEVEL", "INFO"),
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
"<level>{level: <8}</level> | "
"<level>{message}</level>",
)
logger.info(
"biomass_poller 启动 | base={} | interval={}s | GET /api/v1/biomass/real/camera/ 与 /health/result/",
args.base_url.rstrip("/"),
args.interval,
)
asyncio.run(poll_loop(args.base_url, args.interval))
if __name__ == "__main__":
main()