fix(telegram): 修復 Signal Worker 流程 Telegram 通知斷鏈

問題:
- Phase 6 Signal Worker 新架構沒有整合 Telegram 推送
- 決策就緒時 Telegram 完全沒收到通知
- 這是嚴重的監控盲點!

修復:
- 新增 _push_decision_to_telegram() 推送函數
- DecisionManager 決策 READY 時自動推送
- 非阻塞執行 (asyncio.create_task)

Telegram 通知內容:
- 告警來源 (LLM/Expert System)
- 受影響服務
- 建議動作
- 風險等級
- 信心分數

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-03-23 23:22:26 +08:00
parent 29ceb786ca
commit eca3759fde

View File

@@ -28,12 +28,81 @@ from uuid import uuid4
import structlog
from src.core.redis_client import get_redis
from src.core.config import settings
from src.models.incident import Incident
from src.services.openclaw import get_openclaw
logger = structlog.get_logger(__name__)
# =============================================================================
# Telegram 推送 (Phase 6.5: 決策就緒通知)
# =============================================================================
async def _push_decision_to_telegram(
incident: Incident,
proposal_data: dict[str, Any],
) -> None:
"""
決策就緒時推送到 Telegram
Phase 6.5: 整合 Signal Worker 流程與 Telegram 通知
"""
try:
# 延遲導入避免循環依賴
from src.services.telegram_gateway import get_telegram_gateway, TelegramGatewayError
# 檢查是否有設定 Bot Token
if not settings.OPENCLAW_TG_BOT_TOKEN:
logger.debug(
"telegram_push_skipped",
reason="Bot token not configured",
incident_id=incident.incident_id,
)
return
gateway = get_telegram_gateway()
# 從 proposal_data 提取資料
target = incident.affected_services[0] if incident.affected_services else "unknown"
risk_level = proposal_data.get("risk_level", "medium")
action = proposal_data.get("action", proposal_data.get("kubectl_command", ""))
description = proposal_data.get("description", "")
reasoning = proposal_data.get("reasoning", "")
confidence = proposal_data.get("confidence", 0.75)
source = proposal_data.get("source", "unknown")
# 建立 approval_id (使用 incident_id 作為追蹤)
approval_id = f"INC-{incident.incident_id}"
await gateway.send_approval_card(
approval_id=approval_id,
risk_level=risk_level,
resource_name=target[:50],
root_cause=f"[{source.upper()}] {reasoning[:80]}" if reasoning else description[:100],
suggested_action=action[:50] if action else "待分析",
estimated_downtime="5-15 min",
primary_responsibility="INFRA",
confidence=confidence,
namespace=incident.signals[0].labels.get("namespace", "default") if incident.signals else "default",
)
logger.info(
"telegram_decision_pushed",
incident_id=incident.incident_id,
source=source,
risk_level=risk_level,
)
except Exception as e:
# Telegram 失敗不影響主流程
logger.warning(
"telegram_decision_push_failed",
incident_id=incident.incident_id,
error=str(e),
)
# =============================================================================
# Decision States
# =============================================================================
@@ -298,6 +367,13 @@ class DecisionManager:
# 4. 儲存最終結果
await self._save_token(token)
# 5. Phase 6.5: 推送到 Telegram (非阻塞)
if token.state == DecisionState.READY and token.proposal_data:
# 使用 asyncio.create_task 非阻塞執行
asyncio.create_task(
_push_decision_to_telegram(incident, token.proposal_data)
)
return token
async def _dual_engine_analyze(