feat(api): ADR-027 Phase 2 - 簽核/拒絕後自動同步 Incident 狀態
Router 整合點:
- POST /approvals/{id}/sign → on_approval_status_change("approved")
- POST /approvals/{id}/reject → on_approval_status_change("rejected")
- POST /approvals/bulk-approve → 批次同步
變更:
- 移除舊的 resolve_incident_after_approval() 調用
- 改用 IncidentApprovalService.on_approval_status_change()
- 同步失敗不阻斷主流程 (容錯設計)
ADR-027 進度: Phase 1-2 ✅ 完成
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,7 @@ from src.models.approval import (
|
||||
from src.services.approval_db import get_approval_service, get_timeline_service
|
||||
from src.services.approval_execution import get_execution_service
|
||||
from src.services.executor import get_executor
|
||||
from src.services.incident_approval_service import get_incident_approval_service
|
||||
from src.services.proposal_service import get_proposal_service
|
||||
|
||||
router = APIRouter(prefix="/approvals", tags=["HITL Approvals"])
|
||||
@@ -357,41 +358,26 @@ async def sign_approval(
|
||||
execution_svc = get_execution_service()
|
||||
background_tasks.add_task(execution_svc.execute_approved_action, approval)
|
||||
|
||||
# Phase 6.5: 更新關聯的 Incident 狀態為 RESOLVED
|
||||
# 🔴 關鍵: 這是審核後 Incident 狀態更新的核心邏輯
|
||||
incident_id = approval.metadata.get("incident_id") if approval.metadata else None
|
||||
logger.info(
|
||||
"sign_approval_checking_incident",
|
||||
approval_id=str(approval_id),
|
||||
has_metadata=approval.metadata is not None,
|
||||
incident_id=incident_id,
|
||||
metadata_keys=list(approval.metadata.keys()) if approval.metadata else [],
|
||||
)
|
||||
|
||||
if incident_id:
|
||||
proposal_svc = get_proposal_service()
|
||||
resolve_success = await proposal_svc.resolve_incident_after_approval(
|
||||
incident_id=incident_id,
|
||||
# Phase 6.5 + ADR-027: 更新關聯的 Incident 狀態為 RESOLVED
|
||||
# 🔴 2026-03-26: 使用 IncidentApprovalService 確保原子同步
|
||||
try:
|
||||
sync_service = get_incident_approval_service()
|
||||
await sync_service.on_approval_status_change(
|
||||
approval_id=str(approval_id),
|
||||
new_status="approved",
|
||||
)
|
||||
logger.info(
|
||||
"incident_resolved_after_sign",
|
||||
incident_id=incident_id,
|
||||
"incident_approval_synced",
|
||||
approval_id=str(approval_id),
|
||||
success=resolve_success,
|
||||
new_status="approved",
|
||||
)
|
||||
if not resolve_success:
|
||||
logger.error(
|
||||
"incident_resolve_failed",
|
||||
incident_id=incident_id,
|
||||
approval_id=str(approval_id),
|
||||
note="Incident status may not be updated correctly",
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"sign_approval_no_incident_id",
|
||||
except Exception as e:
|
||||
# 同步失敗不阻斷主流程,但記錄錯誤
|
||||
logger.error(
|
||||
"incident_approval_sync_failed",
|
||||
approval_id=str(approval_id),
|
||||
note="Approval has no incident_id in metadata, cannot update Incident status",
|
||||
error=str(e),
|
||||
note="Incident status may not be updated correctly",
|
||||
)
|
||||
|
||||
# SSE: 發布簽核/核准事件
|
||||
@@ -483,6 +469,25 @@ async def reject_approval(
|
||||
reason=request.reason,
|
||||
)
|
||||
|
||||
# ADR-027: 同步更新 Incident 狀態為 rejected
|
||||
try:
|
||||
sync_service = get_incident_approval_service()
|
||||
await sync_service.on_approval_status_change(
|
||||
approval_id=str(approval_id),
|
||||
new_status="rejected",
|
||||
)
|
||||
logger.info(
|
||||
"incident_approval_synced",
|
||||
approval_id=str(approval_id),
|
||||
new_status="rejected",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"incident_approval_sync_failed",
|
||||
approval_id=str(approval_id),
|
||||
error=str(e),
|
||||
)
|
||||
|
||||
# SSE: 發布拒絕事件
|
||||
asyncio.create_task(_publish_approval_event("rejected", approval))
|
||||
|
||||
@@ -614,13 +619,18 @@ async def bulk_approve(
|
||||
bulk_execution_svc = get_execution_service()
|
||||
background_tasks.add_task(bulk_execution_svc.execute_approved_action, signed_approval)
|
||||
|
||||
# 更新關聯的 Incident 狀態
|
||||
incident_id = signed_approval.metadata.get("incident_id") if signed_approval.metadata else None
|
||||
if incident_id:
|
||||
proposal_svc = get_proposal_service()
|
||||
await proposal_svc.resolve_incident_after_approval(
|
||||
incident_id=incident_id,
|
||||
# ADR-027: 同步更新 Incident 狀態
|
||||
try:
|
||||
sync_service = get_incident_approval_service()
|
||||
await sync_service.on_approval_status_change(
|
||||
approval_id=approval_id_str,
|
||||
new_status="approved",
|
||||
)
|
||||
except Exception as sync_err:
|
||||
logger.error(
|
||||
"bulk_incident_sync_failed",
|
||||
approval_id=approval_id_str,
|
||||
error=str(sync_err),
|
||||
)
|
||||
|
||||
# SSE: 發布事件
|
||||
|
||||
Reference in New Issue
Block a user