feat(management): 4h分析链接入管理域滚动段——独立事务隔离/fact活跃会话+宽表+通话滚动3天
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -701,25 +701,27 @@ class SyncScheduler:
|
||||
print(line, flush=True)
|
||||
|
||||
async def _analytics_tick(self) -> None:
|
||||
"""4h 分析链(stat_daily_staff 滚动3天 + 敏感词增量)——异常只记日志不断链。
|
||||
"""4h 分析链(staff 滚动3天 + 敏感词增量 + 管理域滚动)——异常只记日志不断链。
|
||||
|
||||
纯 DB 无浏览器子进程,不抢 ``_page_lock``(DB 写毫秒级;
|
||||
``max_instances=1`` 防自身重叠即可)。与夜间 full_sync 的
|
||||
staff-daily-stats 步骤重叠时,两侧 DELETE+INSERT 在重叠 PK 范围上
|
||||
可能死锁/锁等待——非致命:tick 吞异常下轮重试,夜间脚本无 set -e
|
||||
次日自愈(UNIQUE/PK 幂等只保证串行提交下不重复,不消锁竞争)。
|
||||
两段独立事务:段1 staff+敏感词(既有);段2 管理域(fact 近3天活跃会话
|
||||
+ 宽表/通话 滚动3天,批次F 2026-09-10)。段2 失败只回滚自身,不牵连
|
||||
段1 已提交结果(v2 Task12:指标失败不中断主分析链)。纯 DB 无浏览器
|
||||
子进程,不抢 ``_page_lock``;``max_instances=1`` 防自身重叠即可。与
|
||||
夜间 full_sync 的汇总/管理步重叠时,两侧 DELETE+INSERT 在重叠 PK
|
||||
范围可能锁等待——非致命:tick 吞异常下轮重试,夜间脚本幂等自愈。
|
||||
|
||||
时区:``day_key`` 内部钉死 Asia/Shanghai,喂 UTC epoch
|
||||
(``time.time()*1000``)即无歧义——用 epoch 而非 naive datetime
|
||||
只为读法直接,数学上两者经本地时区往返等价。
|
||||
(``time.time()*1000``)即无歧义。
|
||||
"""
|
||||
from app.storage.summary import day_key
|
||||
|
||||
today = day_key(int(time.time() * 1000))
|
||||
# ── 段1:staff 滚动 + 敏感词增量(既有,语义原样) ──
|
||||
try:
|
||||
async with self._session_maker() as session:
|
||||
from app.analytics.sensitive import scanner
|
||||
from app.storage.staff_summary import recompute_days, rolling_days
|
||||
from app.storage.summary import day_key
|
||||
|
||||
today = day_key(int(time.time() * 1000))
|
||||
n = await recompute_days(session, rolling_days(today, 3))
|
||||
scan = await scanner.run_incremental(session)
|
||||
await session.commit()
|
||||
@@ -730,6 +732,32 @@ class SyncScheduler:
|
||||
except Exception: # noqa: BLE001 — scheduler MUST NOT crash
|
||||
logger.exception("analytics tick failed")
|
||||
|
||||
# ── 段2:管理域滚动(fact 活跃会话 + 宽表/通话,当日+滚动3天) ──
|
||||
try:
|
||||
async with self._session_maker() as session:
|
||||
from app.storage.employee_metrics import (
|
||||
recompute_call_days,
|
||||
recompute_metric_days,
|
||||
)
|
||||
from app.storage.first_reply_facts import (
|
||||
pairs_active_in_days,
|
||||
recompute_pairs,
|
||||
)
|
||||
from app.storage.staff_summary import rolling_days
|
||||
|
||||
rd = rolling_days(today, 3)
|
||||
pairs = await pairs_active_in_days(session, rd)
|
||||
f = await recompute_pairs(session, pairs)
|
||||
w = await recompute_metric_days(session, rd)
|
||||
c = await recompute_call_days(session, rd)
|
||||
await session.commit()
|
||||
logger.info(
|
||||
"[analytics-tick] mgmt fact_pairs=%s wide_rows=%s call_rows=%s",
|
||||
f, w, c,
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
logger.exception("management metrics tick failed")
|
||||
|
||||
async def _page_subprocess(self, args: list[str], *, timeout: float | None = None) -> int:
|
||||
"""启动页面子进程并等待结束;继承环境 + 补 DB_URL/PYTHONIOENCODING。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user