feat(incident): add trigger_reanalysis() with Redis 10min dedup (ADR-050)

This commit is contained in:
OG T
2026-04-01 21:06:39 +08:00
parent 0df2625b26
commit 6dc1505584

View File

@@ -746,6 +746,89 @@ class IncidentService:
)
return None
async def trigger_reanalysis(self, incident_id: str) -> dict:
"""
觸發 Incident 重診 (ADR-050 P2: reanalyze button)
去重保護:同一 incident 10 分鐘內只觸發一次。
觸發後將 incident status 標記為 analyzing等待 AI 自動接手。
Args:
incident_id: Incident ID
Returns:
dict: {
"triggered": bool,
"message": str,
"already_analyzing": bool,
}
2026-04-01 Claude Code (ADR-050 P2): reanalyze button handler
"""
REANALYZE_TTL_SECONDS = 600 # 10 分鐘去重 TTL (ADR-050)
dedup_key = f"reanalyze_dedup:{incident_id}"
try:
redis_client = get_redis()
# 去重檢查 (SETNX: 只有第一次設定會成功)
is_new = await redis_client.set(dedup_key, "1", ex=REANALYZE_TTL_SECONDS, nx=True)
if not is_new:
logger.info(
"reanalyze_deduplicated",
incident_id=incident_id,
reason="Already triggered within 10 minutes",
)
return {
"triggered": False,
"message": "重診已在進行中,請 10 分鐘後再試",
"already_analyzing": True,
}
# 從 Working Memory 取得 Incident
incident = await self.get_from_working_memory(incident_id)
if not incident:
incident = await self.get_from_episodic_memory(incident_id)
if not incident:
# 刪除剛設定的去重 key讓下次能重試
await redis_client.delete(dedup_key)
logger.warning("reanalyze_incident_not_found", incident_id=incident_id)
return {
"triggered": False,
"message": f"找不到事件 {incident_id}",
"already_analyzing": False,
}
# 標記 status 為 analyzing讓 AI 引擎接手)
# 使用延遲 import 避免循環依賴(同 create_incident_from_signal 模式)
from src.models.incident import IncidentStatus
# 使用 INVESTIGATING 若 ANALYZING 不存在
analyzing_status = getattr(IncidentStatus, "ANALYZING", None) or getattr(IncidentStatus, "INVESTIGATING", None)
if analyzing_status:
incident.status = analyzing_status
await self.save_to_working_memory(incident)
logger.info(
"reanalyze_triggered",
incident_id=incident_id,
severity=incident.severity.value,
)
return {
"triggered": True,
"message": "重診已排程AI 正在分析中",
"already_analyzing": False,
}
except Exception as e:
logger.exception("reanalyze_failed", incident_id=incident_id, error=str(e))
return {
"triggered": False,
"message": f"重診觸發失敗: {str(e)[:80]}",
"already_analyzing": False,
}
# =============================================================================
# Singleton