Files
rssKeeper/backend/health_checker.py
T
congsh 54e7db0ef0 feat: init rssKeeper - RSS 抓取、管理与检索系统
完整功能包括:
- FastAPI 后端 + SQLite + FTS5 全文搜索
- RSS 源管理、自动发现、OPML 导入导出
- 文章抓取、去重、分类、全文检索
- RSS 源健康度监控
- Vue 3 + Element Plus 暗色主题 Web UI
- 对外 REST API 供 AI 分析调用
- Docker + docker-compose 部署
2026-06-11 14:03:36 +08:00

113 lines
3.8 KiB
Python

"""RSS 源健康度检测"""
from datetime import datetime, timedelta
from typing import List, Dict
from sqlalchemy.orm import Session
from models import Feed, FetchLog
def get_feed_health(db: Session, feed_id: int = None) -> List[Dict]:
"""获取 RSS 源健康度信息
返回每个源的健康状态详情
"""
query = db.query(Feed)
if feed_id:
query = query.filter(Feed.id == feed_id)
feeds = query.all()
results = []
for feed in feeds:
total = feed.success_count + feed.fail_count
success_rate = round(feed.success_count / total * 100, 1) if total > 0 else 0
days_since_fetch = None
if feed.last_fetch_at:
days_since_fetch = (datetime.utcnow() - feed.last_fetch_at).days
# 获取最近 7 天抓取记录
recent_logs = db.query(FetchLog).filter(
FetchLog.feed_id == feed.id,
FetchLog.created_at >= datetime.utcnow() - timedelta(days=7)
).order_by(FetchLog.created_at.desc()).limit(10).all()
health = feed.health_status()
results.append({
"id": feed.id,
"title": feed.title or feed.url,
"url": feed.url,
"is_active": feed.is_active,
"health_status": health,
"health_label": _health_label(health),
"success_rate": success_rate,
"success_count": feed.success_count,
"fail_count": feed.fail_count,
"total_fetches": total,
"last_fetch_at": feed.last_fetch_at.isoformat() if feed.last_fetch_at else None,
"days_since_fetch": days_since_fetch,
"article_count": feed.article_count,
"last_error": feed.last_error,
"recent_logs": [
{
"status": log.status,
"articles_fetched": log.articles_fetched,
"response_time_ms": log.response_time_ms,
"created_at": log.created_at.isoformat(),
"error_message": log.error_message if log.status == "fail" else None,
}
for log in recent_logs
],
})
return results
def _health_label(status: str) -> str:
labels = {
"healthy": "健康",
"warning": "警告",
"unhealthy": "异常",
"unknown": "未知",
}
return labels.get(status, "未知")
def get_overall_stats(db: Session) -> Dict:
"""获取整体统计信息"""
total_feeds = db.query(Feed).count()
active_feeds = db.query(Feed).filter(Feed.is_active == True).count()
total_articles = db.query(Feed).with_entities(Feed.article_count).all()
total_articles_count = sum(a[0] for a in total_articles) if total_articles else 0
# 健康源统计
feeds = db.query(Feed).all()
healthy = warning = unhealthy = 0
for feed in feeds:
status = feed.health_status()
if status == "healthy":
healthy += 1
elif status == "warning":
warning += 1
elif status == "unhealthy":
unhealthy += 1
# 今日抓取
today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
from models import FetchLog
today_fetches = db.query(FetchLog).filter(FetchLog.created_at >= today).count()
today_success = db.query(FetchLog).filter(
FetchLog.created_at >= today, FetchLog.status == "success"
).count()
return {
"total_feeds": total_feeds,
"active_feeds": active_feeds,
"total_articles": total_articles_count,
"healthy_feeds": healthy,
"warning_feeds": warning,
"unhealthy_feeds": unhealthy,
"today_fetches": today_fetches,
"today_success": today_success,
"today_success_rate": round(today_success / today_fetches * 100, 1) if today_fetches > 0 else 0,
}