o2o-site-AEO/solution/backend/services/search_console_alerts.py
Mina Choi 3f47d5ecd2 [feat] solution/backend: 서치콘솔 자동 제출·색인 상태 추적 추가
사이트 발행 성공과 Google 색인 관측은 별도 상태다. 외부 API 장애로 발행이 실패하거나 재시작 때 추적 정보가 사라지지 않도록 분리.

- Google 클라이언트·배치·DB·Teams 알림 모듈 분리
- 기존 스케줄러 연결, 재시도·중복 실행 방지와 선택 설정 추가
- ORM·초기 DDL·마이그레이션·운영 설정 문서 동시 갱신

검증: 관련 59건 통과, compose 설정·diff 검사 통과. 추가 회귀 23건 통과, 기존 발행 검수 실패 1건은 변경 전 코드에서도 재현. 운영 배포·Google/Teams 실호출 미실행.
2026-09-15 14:50:30 +09:00

44 lines
1.7 KiB
Python

"""Teams Workflow 수신용. 원문 오류/인증 정보는 메시지에 싣지 않는다."""
from datetime import timedelta
import httpx
from common.logger import LOG
def alert_reason(row, now, days: int) -> str | None:
if row.alerted_at and now - row.alerted_at < timedelta(days=1):
return None
if row.error_code:
return f"조회/제출 실패: {row.error_code}"
if (row.inspection or {}).get("verdict") == "PASS":
return None
if now - row.published_at >= timedelta(days=days):
return f"발행 후 {days}일 이상 색인 미확인"
return None
async def send_alert(webhook_url: str, page_url: str, reason: str) -> bool:
if not webhook_url:
return False
if not webhook_url.startswith("https://"):
LOG.w("[search-console] ALERT_URL_INVALID")
return False
payload = {"type": "message", "attachments": [{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {"type": "AdaptiveCard", "version": "1.2", "body": [
{"type": "TextBlock", "text": "Google 색인 확인 필요", "weight": "Bolder"},
{"type": "TextBlock", "text": page_url, "wrap": True},
{"type": "TextBlock", "text": reason, "wrap": True},
]},
}]}
try:
async with httpx.AsyncClient(timeout=10, follow_redirects=False) as client:
response = await client.post(webhook_url, json=payload)
response.raise_for_status()
return True
except httpx.HTTPError:
# webhook 주소 자체가 인증 수단이므로 예외 문자열도 로그에 남기지 않는다.
LOG.w("[search-console] ALERT_DELIVERY_FAILED")
return False