b2c20ec43d
- 新增微信告警服务(wechat_service)和告警任务(alert_tasks) - 新增 WebSocket 实时推送端点 - 新增监控管理模块(monitor) - 增强统计仪表板:趋势图、区域分布、光功率历史 - 设备管理:添加坐标信息、标签系统、复合索引优化 - 前端:重构Dashboard/Charts页面,新增业务组件 - 新增5个数据库迁移(坐标、复合索引、标签、光功率历史、显示名) - 更新部署配置和脚本 - 新增测试框架基础结构
83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
"""告警相关 Celery 任务"""
|
||
import traceback
|
||
from datetime import datetime
|
||
from sqlalchemy import func, case
|
||
from app.core.celery_app import celery_app
|
||
from app.core.database import SessionLocal
|
||
|
||
|
||
@celery_app.task(queue='h3c_onu_ms', ignore_result=True)
|
||
def check_school_offline_alerts():
|
||
"""
|
||
检查是否有学校全部离线(在线率为 0%),如有则发送企业微信告警。
|
||
该任务在每次全量状态检查完成后异步调用。
|
||
"""
|
||
from app.models.device import ONUDevice, DeviceStatusHistory
|
||
from app.services.wechat_service import send_wechat_markdown
|
||
|
||
db = SessionLocal()
|
||
try:
|
||
# 每台设备最新状态的子查询
|
||
latest_subq = (
|
||
db.query(
|
||
DeviceStatusHistory.onu_device_id,
|
||
func.max(DeviceStatusHistory.checked_at).label("max_checked_at")
|
||
)
|
||
.group_by(DeviceStatusHistory.onu_device_id)
|
||
.subquery()
|
||
)
|
||
latest_status_subq = (
|
||
db.query(
|
||
DeviceStatusHistory.onu_device_id,
|
||
DeviceStatusHistory.status
|
||
)
|
||
.join(
|
||
latest_subq,
|
||
(DeviceStatusHistory.onu_device_id == latest_subq.c.onu_device_id) &
|
||
(DeviceStatusHistory.checked_at == latest_subq.c.max_checked_at)
|
||
)
|
||
.subquery()
|
||
)
|
||
|
||
# 按学校聚合在线率,只查询在线数为 0 的学校
|
||
rows = (
|
||
db.query(
|
||
ONUDevice.school_name,
|
||
ONUDevice.region,
|
||
func.count().label("total"),
|
||
func.sum(case((latest_status_subq.c.status == 'online', 1), else_=0)).label("online"),
|
||
)
|
||
.outerjoin(latest_status_subq, ONUDevice.id == latest_status_subq.c.onu_device_id)
|
||
.group_by(ONUDevice.school_name, ONUDevice.region)
|
||
.having(
|
||
func.sum(case((latest_status_subq.c.status == 'online', 1), else_=0)) == 0
|
||
)
|
||
.all()
|
||
)
|
||
|
||
if not rows:
|
||
return {"alerted": False, "reason": "没有全离线的学校"}
|
||
|
||
# 构造告警消息
|
||
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
lines = [
|
||
"## <font color=\"warning\">[告警] 学校全部离线</font>",
|
||
f"> 检查时间:{now_str}",
|
||
"> 以下学校所有设备均处于离线状态:",
|
||
"",
|
||
]
|
||
for row in rows:
|
||
school = row.school_name or "未知"
|
||
region = row.region or "未知"
|
||
total = int(row.total or 0)
|
||
if total > 0:
|
||
lines.append(f"- **{school}**({region}): {total} 台设备全离线")
|
||
|
||
content = "\n".join(lines)
|
||
send_wechat_markdown(content)
|
||
return {"alerted": True, "schools": len(rows)}
|
||
except Exception as e:
|
||
return {"alerted": False, "error": str(e), "traceback": traceback.format_exc()}
|
||
finally:
|
||
db.close()
|