feat(scripts): add biomass_poller with httpx and loguru
Poll GET /api/v1/biomass/real/camera/ and /health/result/; add loguru to fish_api dev deps. Made-with: Cursor
This commit is contained in:
@@ -11,7 +11,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["httpx>=0.28.1"]
|
||||
dev = ["httpx>=0.28.1", "loguru>=0.7.0"]
|
||||
|
||||
[project.scripts]
|
||||
fish-action-watch = "app.action_watch_cli:main"
|
||||
|
||||
92
scripts/biomass_poller.py
Executable file
92
scripts/biomass_poller.py
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/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
|
||||
|
||||
|
||||
async def poll_once(client: httpx.AsyncClient, base: str) -> None:
|
||||
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)
|
||||
logger.info(
|
||||
"[real/camera/] HTTP {} | {}",
|
||||
r1.status_code,
|
||||
json.dumps(_fmt_body(r1), ensure_ascii=False),
|
||||
)
|
||||
logger.info(
|
||||
"[health/result/] HTTP {} | {}",
|
||||
r2.status_code,
|
||||
json.dumps(_fmt_body(r2), ensure_ascii=False),
|
||||
)
|
||||
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user