fix(playbook+flywheel): 修復 PlaybookSource enum + repair_steps 相容 + KM stats raw SQL
修復三個串聯 bug,讓 Playbook seed 能正常執行: 1. PlaybookSource 新增 YAML_RULE enum(alert_rules.yaml 匯入專用) 2. playbook_seed_service: source=YAML_RULE,dedup 改用 raw SQL by name, 不再呼叫 list_playbooks(舊格式 repair_steps 會 validation error) 3. playbook_repository._orm_to_pydantic: 舊格式 repair_steps 補齊 step_number/action_type 必填欄位(向下相容) 4. flywheel_stats_service: embedding IS NULL 改用 raw SQL, 修復 KnowledgeEntryRecord ORM 無 embedding 屬性的 AttributeError Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -225,8 +225,10 @@ class FlywheelStatsService:
|
||||
|
||||
async with get_db_context() as db:
|
||||
# 未向量化數量 (embedding IS NULL = 未向量化)
|
||||
# 2026-04-15 ogt: KnowledgeEntryRecord ORM 不宣告 embedding 欄位(pgvector),
|
||||
# 改用 raw SQL 避免 AttributeError
|
||||
unvectorized_q = await db.execute(
|
||||
select(func.count()).where(KnowledgeEntryRecord.embedding.is_(None))
|
||||
text("SELECT COUNT(*) FROM knowledge_entries WHERE embedding IS NULL")
|
||||
)
|
||||
unvectorized = unvectorized_q.scalar_one_or_none() or 0
|
||||
|
||||
|
||||
@@ -42,15 +42,22 @@ async def seed_playbooks_from_rules() -> None:
|
||||
|
||||
repo = get_playbook_repository()
|
||||
|
||||
# 取得現有 playbook source_ids,避免重複建立
|
||||
existing, _ = await repo.list_playbooks(status=PlaybookStatus.APPROVED, limit=500)
|
||||
existing_sources = {p.source for p in existing if p.source}
|
||||
# 取得現有 YAML_RULE playbook,依 name 去重避免重複建立
|
||||
# 2026-04-15 ogt: 不再用 list_playbooks(舊格式 repair_steps 會 validation error)
|
||||
# 改用 raw SQL 只撈 name 欄位,更穩健
|
||||
from src.db.session import get_db_context
|
||||
from sqlalchemy import text as sa_text
|
||||
async with get_db_context() as db:
|
||||
rows = await db.execute(
|
||||
sa_text("SELECT name FROM playbooks WHERE source = 'yaml_rule'")
|
||||
)
|
||||
existing_names = {r[0] for r in rows.fetchall()}
|
||||
|
||||
seeded = 0
|
||||
for rule in rules:
|
||||
rule_id = rule.get("id", "")
|
||||
source_key = f"alert_rule:{rule_id}"
|
||||
if source_key in existing_sources:
|
||||
rule_name = rule.get("description", rule_id)
|
||||
if rule_name in existing_names:
|
||||
continue
|
||||
|
||||
resp = rule.get("response", {})
|
||||
@@ -71,7 +78,7 @@ async def seed_playbooks_from_rules() -> None:
|
||||
name=rule.get("description", rule_id),
|
||||
description=resp.get("description", rule.get("description", "")),
|
||||
status=PlaybookStatus.APPROVED,
|
||||
source=source_key,
|
||||
source=PlaybookSource.YAML_RULE,
|
||||
symptom_pattern=SymptomPattern(
|
||||
alert_names=alertnames,
|
||||
affected_services=[],
|
||||
|
||||
Reference in New Issue
Block a user