feat(telegram): enforce canonical product routing

This commit is contained in:
ogt
2026-07-14 19:14:11 +08:00
parent 1431abba54
commit 180e708444
54 changed files with 7746 additions and 740 deletions

View File

@@ -569,38 +569,114 @@ class ReportGenerationService:
Graceful Degradation: 失敗只記錄 log不拋出例外
"""
try:
from src.services.telegram_gateway import (
_telegram_send_delivery_succeeded,
get_telegram_gateway,
)
gateway = get_telegram_gateway()
if not gateway.canonical_destination_chat_id(
product_id="awoooi",
signal_family="product_raw_monitoring",
severity="P3",
):
logger.warning(
"daily_report_no_send",
reason="canonical_route_unavailable",
)
return
kpi = await self.collect_daily_kpi()
source_health = await self.collect_report_source_health(days=1)
report_text = self.format_daily_report(kpi, source_health)
from src.services.telegram_gateway import get_telegram_gateway
gateway = get_telegram_gateway()
await gateway.send_to_group(report_text, parse_mode="HTML")
logger.info(
"daily_report_sent",
total_alerts=kpi.total_alerts,
auto_repair_rate=f"{kpi.auto_repair_rate:.1%}",
result = await gateway.send_to_group(
report_text,
parse_mode="HTML",
product_id="awoooi",
signal_family="product_raw_monitoring",
severity="P3",
)
if _telegram_send_delivery_succeeded(result):
logger.info(
"daily_report_sent",
total_alerts=kpi.total_alerts,
delivery_status=result.get("_awooop_delivery_status", "sent"),
auto_repair_rate=f"{kpi.auto_repair_rate:.1%}",
)
else:
logger.warning(
"daily_report_no_send",
total_alerts=kpi.total_alerts,
delivery_status=(
result.get(
"_awooop_delivery_status",
"missing_provider_ack",
)
if isinstance(result, dict)
else "missing_provider_ack"
),
)
except Exception as e:
logger.error("daily_report_failed", error=str(e))
async def send_monthly_report(self) -> bool:
"""收集月報資料 → 組裝 → 推送 Telegram SRE 群組。"""
try:
from src.services.telegram_gateway import (
_telegram_send_delivery_succeeded,
get_telegram_gateway,
)
gateway = get_telegram_gateway()
if not gateway.canonical_destination_chat_id(
product_id="awoooi",
signal_family="product_raw_monitoring",
severity="P3",
):
logger.warning(
"monthly_report_no_send",
reason="canonical_route_unavailable",
)
return False
source_health = await self.collect_report_source_health(days=30)
report_text = self.format_monthly_report(source_health)
from src.services.telegram_gateway import get_telegram_gateway
gateway = get_telegram_gateway()
await gateway.send_to_group(report_text, parse_mode="HTML")
logger.info(
"monthly_report_sent",
source_ok=(source_health.get("rollups") or {}).get("source_ok_count"),
source_total=(source_health.get("rollups") or {}).get("source_count"),
result = await gateway.send_to_group(
report_text,
parse_mode="HTML",
product_id="awoooi",
signal_family="product_raw_monitoring",
severity="P3",
)
return True
if _telegram_send_delivery_succeeded(result):
logger.info(
"monthly_report_sent",
source_ok=(source_health.get("rollups") or {}).get(
"source_ok_count"
),
delivery_status=result.get("_awooop_delivery_status", "sent"),
source_total=(source_health.get("rollups") or {}).get(
"source_count"
),
)
return True
logger.warning(
"monthly_report_no_send",
delivery_status=(
result.get(
"_awooop_delivery_status",
"missing_provider_ack",
)
if isinstance(result, dict)
else "missing_provider_ack"
),
)
return False
except Exception as e:
logger.error("monthly_report_failed", error=str(e))
return False
@@ -663,7 +739,10 @@ class ReportGenerationService:
import asyncio as _asyncio
report_text = self.format_postmortem(data)
await self._persist_postmortem_km(data, report_text)
from src.services.telegram_gateway import get_telegram_gateway
from src.services.telegram_gateway import (
_telegram_send_delivery_succeeded,
get_telegram_gateway,
)
gateway = get_telegram_gateway()
max_attempts = 3
@@ -671,7 +750,22 @@ class ReportGenerationService:
last_error: Exception | None = None
for attempt in range(1, max_attempts + 1):
try:
await gateway.send_to_group(report_text, parse_mode="HTML")
result = await gateway.send_to_group(
report_text,
parse_mode="HTML",
product_id="awoooi",
signal_family="incident_lifecycle",
severity="P1",
)
if not _telegram_send_delivery_succeeded(result):
delivery_status = (
result.get("_awooop_delivery_status")
if isinstance(result, dict)
else None
)
raise RuntimeError(
str(delivery_status or "missing_provider_ack")
)
logger.info(
"postmortem_sent",
incident_id=incident_id,
@@ -705,7 +799,23 @@ class ReportGenerationService:
f"Duration: {duration_minutes:.1f} 分鐘\n"
f"Error: {str(last_error)[:200]}"
)
await gateway.send_to_group(fallback_text, parse_mode="HTML")
fallback_result = await gateway.send_to_group(
fallback_text,
parse_mode="HTML",
product_id="awoooi",
signal_family="incident_lifecycle",
severity="P1",
)
if not _telegram_send_delivery_succeeded(fallback_result):
logger.error(
"postmortem_fallback_no_send",
incident_id=incident_id,
delivery_status=(
fallback_result.get("_awooop_delivery_status")
if isinstance(fallback_result, dict)
else "missing_provider_ack"
),
)
except Exception as _fe:
logger.error(
"postmortem_fallback_failed",