4cfc2fa6a9
Co-Authored-By: Claude Code <noreply@anthropic.com>
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
"""E0-lite 数据健康——「数据截至」角标 + 实体新鲜度。
|
|
|
|
完整 E0(调度日志解析/成功率账本)二批;v1 用表新鲜度判定:
|
|
msg_daily_stats 当日有行 = 4h 消息链路活着。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
from typing import Any
|
|
|
|
import sqlalchemy as sa
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.db.models import (
|
|
ChatGroup,
|
|
Customer,
|
|
Media,
|
|
Message,
|
|
MomentsPost,
|
|
MsgDailyStats,
|
|
PhoneCall,
|
|
)
|
|
|
|
|
|
async def data_as_of(session: AsyncSession) -> int | None:
|
|
"""数据截至(ms-epoch)= MAX(msg_daily_stats.last_ts)。
|
|
|
|
漏迁移导致表缺失时按 500 响亮报错是有意的——本模块是诊断端点,
|
|
要暴露部署问题而非掩盖(0ade58a 的空表静默守卫是业务端点的容错,
|
|
别好心搬到这里)。
|
|
"""
|
|
val = (
|
|
await session.execute(sa.select(sa.func.max(MsgDailyStats.last_ts)))
|
|
).scalar_one_or_none()
|
|
return int(val) if val is not None else None
|
|
|
|
|
|
async def entity_freshness(session: AsyncSession) -> list[dict[str, Any]]:
|
|
"""各实体最后更新时间(UPDATED_AT 列 MAX;message 用 fetched_at)。
|
|
|
|
同 data_as_of:表缺失按 500 响亮报错是有意的(诊断端点不容错)。
|
|
"""
|
|
|
|
async def _max(col) -> dt.datetime | None:
|
|
return (await session.execute(sa.select(sa.func.max(col)))).scalar_one_or_none()
|
|
|
|
out = []
|
|
for name, col in (
|
|
("customer", Customer.updated_at),
|
|
("chat_group", ChatGroup.updated_at),
|
|
("phone_call", PhoneCall.updated_at),
|
|
("media", Media.updated_at),
|
|
("moments_post", MomentsPost.updated_at),
|
|
("message", Message.fetched_at),
|
|
):
|
|
out.append({"table": name, "last_seen": await _max(col)})
|
|
return out
|