본문으로 건너뛰기

Drift Breach Notification Dispatch (#1284 G-1 M3)

apps/api/src/gend_api/services/drift_service.pycompute_and_persist()drift_status == "breach" 시 자동으로 NotificationService.dispatch() 호출 — Slack/Email/Webhook/GenOS 채널 중 등록된 채널에 알림 발송.

디자인 결정

1. 왜 fire-and-forget?

  • DriftReport 저장이 알림 발송 실패에 영향받지 않아야 함
  • try/except + logger.exception (Audit middleware _fire_and_forget 패턴)
  • 알림 실패 시 drift_report.notified_at = None 유지 (재시도 추적용)

2. 왜 NotificationService 추상화 활용?

  • provider-agnostic (Slack/Email/Webhook/GenOS/Telegram)
  • 환경별 선택 가능 (on-prem 가스공사: Email/Webhook 권장)
  • 신규 provider 추가 시 drift_service 코드 변경 0

3. 왜 event_type="drift.breach"?

  • NotificationChannel.events 배열로 채널이 구독할 이벤트 필터링
  • 워크스페이스 admin 이 "drift 만 받기" / "drift+model.predict.denied 받기" 등 세밀 제어

코드 핵심

async def compute_and_persist(self, ...):
report = await self.compute_drift(reference, current, threshold)
db_row = await self._persist(report)

if report.drift_status == "breach":
try:
event = NotificationEvent(
event_type="drift.breach",
title=f"Drift breach: {model_name}@{model_version}",
message=self._format_message(report),
metadata={
"model_name": model_name,
"drift_score": report.drift_score,
"drifted_features": report.drifted_features[:3],
"report_url": f"/admin/drift/{db_row.id}",
},
)
result = await NotificationService.dispatch(event, self._db)
if any(r.success for r in result):
db_row.notified_at = datetime.utcnow()
await self._db.commit()
except Exception:
logger.exception("drift breach notification dispatch failed (silent)")
return db_row

환경별 권장 Provider

환경Providerwebhook URL/SMTP 출처
GenD prod (Azure)SlackSlack workspace admin 발급 webhook
on-prem 가스공사Email사내 SMTP (smtp.kogas.co.kr)
on-prem 일반WebhookMattermost/Rocket.Chat hooks
폐쇄망GenOSGenOS user_group 내부 알림

자세한 가이드: notification-provider-guide

회귀 가드 — 7 tests

apps/api/tests/test_drift_breach_notification.py:

  • breach → dispatch 호출 + event_type="drift.breach"
  • ok / warn → dispatch 호출 X
  • dispatch 실패 → drift_report 정상 저장 (notified_at=None)
  • dispatch 성공 → notified_at 갱신
  • empty drifted_features 안전 (KeyError X)
  • message body 에 features 상위 3개 표기

트러블슈팅

증상원인해결
breach 인데 알림 안 옴NotificationChannel 미등록POST /api/v1/notification/channels
Webhook 401webhook URL 만료/회전Slack workspace re-issue
notified_at 항상 NoneNotificationService.dispatch silent failgend-api log gend.audit 확인
메시지에 features 누락DriftReport.drifted_features 빈 listDriftService.compute_drift threshold 조정

관련