1. ChatGPT Apps 세계에서 인시던트란 무엇인가
클래식 웹에서는 인시던트가 보통 “서버가 죽었다”, “500 에러가 급증했다”, “지연(latency)이 두 배로 늘었다”와 같은 상황을 말합니다. ITIL의 공식 정의로는 인시던트는 서비스의 계획되지 않은 중단 또는 서비스 품질의 저하입니다.
ChatGPT Apps와 GiftGenius의 세계는 더 복잡합니다. 모델 레이어가 생기면서 다음과 같은 일이 벌어질 수 있습니다:
- 모든 것이 가능함에도 필요한 tool을 호출하지 않거나;
- tool을 잘못된 파라미터로 호출하거나;
- 여러분의 MCP를 무시하고 결과를 “환각”으로 만들어내기도 합니다.
따라서 인시던트는 HTTP 500뿐만 아니라, 모든 백엔드 메트릭이 초록불인데도 사용자가 대거 불만을 제기하는 상황 — “봇이 멍청하고 선물을 안 보여줘요” — 도 포함됩니다. 이는 모델이 suggest_gifts 호출을 멈추거나 인자를 혼동했기 때문일 수 있습니다. 이것이 바로 품질 인시던트(Quality incident)입니다.
인시던트를 카테고리로 나눠 생각하면 편합니다:
| 카테고리 | 증상 예시 | 메트릭 예시 (SLI) |
|---|---|---|
| Availability | MCP가 응답하지 않음, ChatGPT에서 “Error talking to app” 표시 | % 성공 응답 /mcp |
| Latency | 선물 추천에 10초 이상 소요 | suggest_gifts 호출 시간의 p95 |
| Quality | 모델이 필요한 tool을 호출하지 않거나 통화를 혼동함 | 명시적 요청에도 tool-call이 없는 요청 비율 |
| Commerce | 결제가 진행되지 않음, 돈이 이동하지 않음 | checkout_success_rate |
인시던트란 사전에 합의한 SLO의 경계를 실제 메트릭이 벗어나는 순간입니다. 예를 들어:
- 합의: 선물 추천의 p95 < 4초. 실제: 9초가 됨;
- 주당 checkout 99% 성공을 원했지만 94%로 떨어짐;
- 구매 시나리오에서 모델이 거의 항상 create_checkout_session을 호출해야 하는데, 로그에서 “누락”이 급증함.
중요: 인시던트는 “누군가 채팅에서 불평했다”가 아닙니다. 불만은 트리거일 뿐이며, “네, 이것은 인시던트다”라는 판단은 SLO/SLI와 대시보드를 근거로 내립니다.
2. SLO/SLI가 어떻게 인시던트로 전환되는가
Observability 모듈에서 이미 latency, availability, error-rate, 결제 성공과 같은 핵심 메트릭을 설정했습니다. 이제 이들을 “문 앞의 경비”처럼 사용합니다.
가장 단순한 시나리오: checkout_success_rate에 대한 SLO가 있습니다. 우리는 이벤트를 구조적 로그로 남깁니다:
// MCP 서버의 checkout 로그 이벤트 예시
logger.info({
event: 'checkout_result',
request_id,
user_id,
checkout_session_id,
status: 'success', // 또는 'failed'
error_code: null,
});
이 로그 위에 메트릭을 만듭니다: 최근 N분/시간 동안 모든 checkout_result 중 status = "success"의 비율. 이 비율이 임계치(예: 10분 동안 95%) 아래로 내려가면 모니터링이 on-call 채널로 알림을 보냅니다. 이것이 바로 인시던트 감지입니다: SLI가 SLO의 범위를 벗어난 것이죠.
다음과 같은 조건으로도 알림이 발생할 수 있습니다:
- suggest_gifts, search_products 도구의 error_rate 상승;
- p95/p99 latency 상승;
- workflow_completed 수의 비정상적 하락(사람들이 시나리오를 끝까지 완료하지 못함);
- 트래픽 증가 없이 LLM 비용이 비정상적으로 급등(경제적 인시던트).
이 모든 것은 우리가 로그를 구조적으로 기록하고, “checkout이 또 뭔가 이상함” 같은 식으로 쓰지 않기 때문에 가능합니다. 메트릭과 알림이 설정되면, 무엇이 잘못되기 시작했는지 알아챌 수 있습니다. 다음 질문은: 감지 후에 무엇이 일어나며, 누가 어떻게 대응하는가 입니다.
3. 인시던트 라이프사이클: 감지부터 포스트모템까지
영원한 화재 진압 모드에서 벗어나려면, 인시던트의 표준 파이프라인을 정의하는 것이 좋습니다. 많은 SRE 팀이 이를 다음과 같은 체인으로 공식화합니다:
flowchart TD
D["Detection (감지)"] --> T["Triage (심각도 평가)"]
T --> M["Mitigation (신속한 피해 완화)"]
M --> R["Resolution (최종 수정)"]
R --> P["Post-mortem (분석과 개선)"]
GiftGenius 예시로 각 단계를 살펴봅니다.
Detection — 어떻게 문제가 심각한지 파악할까
문제의 파악은 자동과 수동으로 나뉩니다.
자동 감지 — SLO/SLI 기반 모니터링 알림입니다:
- PagerDuty / Opsgenie / 이메일 / Slack 봇이 외침: SEV-1: checkout_success_rate < 60% (10분 기준);
- 지연 알림: p95(suggest_gifts) > 10초;
- 비용 이상: “같은 workflow_completed 수인데 LLM 비용이 2배 증가”.
수동 감지 — 지원 채널(혹은 텔레그램으로 여러분에게 직접)로 “결제가 안 돼요”, “위젯이 끝없이 로딩만 해요” 같은 메시지가 쏟아지는 경우입니다. 때로는 모니터링이 따라잡기 전에 이런 제보가 문제를 더 빨리 비춥니다.
실용적 결론: 아직 완벽한 모니터링이 없더라도, 사용자들의 대량 불만을 메트릭의 관점으로 바라보는 습관을 들이세요. “이 뒤에 어떤 메트릭이 있으며, 어떻게 측정할 수 있지?”
Triage — 분류와 우선순위 결정
감지 후에는 두 가지 질문에 답해야 합니다: 얼마나 심각한가, 그리고 누가 뛰어들어 고칠 것인가.
간단한 심각도 척도를 두면 편리합니다:
- SEV-1: 치명적 — 사용자가 결제할 수 없고, App이 핵심 시나리오에서 동작하지 않음(예: 트래픽이 살아 있는데 checkout=0).
- SEV-2: 심각하나 성능 저하 수준 — 일부 사용자가 시나리오를 완료하지 못하고, 지연이 크게 증가했지만 완전 중단은 아님.
- SEV-3: 경미한 버그 — 보조 tool 중 하나가 가끔 실패하거나, 엣지 케이스만 깨짐.
GiftGenius에서 커머스 인시던트는 거의 항상 SEV-1입니다. 돈이 움직이지 않으면 단순 기술 문제가 아니라 매출과 신뢰에 대한 직접적인 피해입니다.
이 단계에서 on-call 담당자를 지정(혹은 1인 팀이면 본인)하고 결정합니다: “네, 공식 SEV‑1 인시던트입니다. 런북 N에 따라 진행합니다”(런북은 사전에 작성된 단계별 지침이며, 구조는 별도 섹션에서 다룹니다).
Mitigation — “출혈”을 멈추기
Mitigation은 근본 원인 조사라기보다, 사용자의 고통을 신속히 줄이는 조치입니다. 예시:
- 최근 MCP/Agents/ACP 릴리스 롤백;
- 문제의 feature flag 비활성화;
- GiftGenius를 “뷰어 모드”로 전환: 추천은 보여주되 구매는 못 하게 함;
- 일시적 부하 완화(rate limiting) 또는 무거운 도구 비활성화.
우리 MCP에서 “디그레이드 모드”를 위한 전형적 코드 예시:
// 의사 코드: 빠르게 전환 가능한 전역 플래그
let checkoutDisabled = false;
export function setCheckoutDisabled(value: boolean) {
checkoutDisabled = value;
}
export async function createCheckoutSession(args: CheckoutArgs) {
if (checkoutDisabled) {
// 모델에 구매가 일시적으로 불가능함을 알림
return {
error: 'checkout_temporarily_disabled',
message: '결제가 일시적으로 불가능합니다. 사용자에게 설명을 보여 주세요.',
};
}
// 세션 생성의 일반 로직
}
feature flag 시스템에서 mitigation의 일부로 setCheckoutDisabled(true)를 호출할 수 있습니다. 그러면 사용자는 500 오류나 멈춘 결제를 겪지 않고, 솔직한 메시지를 보게 됩니다.
Resolution — 최종 수정
“출혈을 멈춘” 뒤에는 근본 원인을 찾아 수정할 시간이 생깁니다:
- MCP/ACP 코드 버그;
- 외부 제공자 문제(Stripe, 결제 게이트웨이);
- OpenAI API 한도(429, 과부하);
- 깨진 프롬프트 또는 변경된 모델이 더 이상 tool을 호출하지 않음.
Resolution에는 보통 다음이 포함됩니다:
- 수정(패치/롤백/설정 변경);
- staging 배포 후 production 배포;
- 모든 SLI/SLO 확인;
- 플래그를 정상 상태로 되돌림.
Post-mortem — 실수에서 배우기
특히 SEV‑1/SEV‑2 인시던트 후에는 포스트모템을 진행합니다. 다음 질문에 솔직히 답하는 문서입니다:
- 무엇이 발생했는가(사실과 타임라인);
- 어떻게 이를 알아챘는가;
- 어떻게 대응했는가;
- 무엇이 잘 작동했으며, 무엇이 잘 안 됐는가;
- 재발 방지를 위해 어떤 변경을 할 것인가.
포스트모템은 누군가를 탓하기 위한 것이 아니라 시스템과 프로세스를 개선하기 위한 것입니다. 이를 바탕으로 런북, 알림, 그리고 때로는 아키텍처까지 업데이트합니다.
4. 역할과 책임: 여러분이 “1인 팀”일지라도
위에서 설명한 인시던트 파이프라인이 현실에서 잘 작동하려면, 화재 상황에서 누가 어떤 결정을 맡는지 미리 합의하는 것이 중요합니다. 한 엘리베이터에 탈 정도로 작은 팀이라도, 인시던트 시의 역할을 형식화하는 것이 혼선을 줄입니다.
일반적으로 다음을 구분합니다:
- On-call 엔지니어 — 알림을 가장 먼저 받고, 안정화를 위한 기술적 결정을 내리는 사람(롤백, feature flag, 임시 우회 등).
- Incident commander — 프로세스를 이끄는 사람: 타임라인을 기록하고, 작업 우선순위를 결정하며, 팀이 우왕좌왕하지 않도록 관리. 마이크로팀에서는 on-call과 동일인이 “다른 모자”를 쓰고 맡을 수 있습니다.
- 커뮤니케이션 — 사용자와 비즈니스 이해관계자와의 소통을 담당: Slack, 상태 페이지, App UI(위젯/채팅), ChatGPT 스토어의 공지.
- Scribe — 중요한 단계와 사실을 기록하고, 이를 바탕으로 포스트모템을 작성.
1인 팀이라면 이 네 가지 역할을 모두 여러분이 맡습니다. 다만 의식적으로 모드를 전환하는 것이 유익합니다: “지금은 엔지니어로서 고친다”, “지금은 소통한다”, “지금은 타임라인을 기록한다”.
5. Runbook: 기억 대신 규범
런북은 특정 유형의 인시던트에서 무엇을 할지 단계별로 정리한 문서입니다: 어떤 그래프를 보고, 어떤 버튼을 누르며, 무엇을 포기할 수 있는지 등. 즉흥성을 크게 줄이고 스트레스를 낮춥니다.
런북 구조
일반적으로 런북에는 다음이 포함됩니다:
- 인시던트의 간단한 설명과 감지 방법. 예: “ACP checkout 오류 증가 > 5% (5분)” 또는 “요청의 >20%에서 Error talking to app”.
- Scope — 영향 범위: 전체 트래픽, 특정 지역, 특정 tool만 등.
- 어디서 볼지: 대시보드 링크(checkout SLO, MCP error-rate, tool_name = create_checkout_session 로그), MCP Inspector 등.
- 신속 완화 단계: “Stripe 상태 확인”, “최근 ACP 릴리스 롤백”, “구매 불가 추천 전용 모드 활성화”.
- 최종 분석 및 수정 단계.
- 사후 업데이트 항목: 알림, 코드, 문서.
GiftGenius용 미니 런북 예시(결제가 실패함)
코드에 가깝게 보이도록 구조화된 데이터 형태로 서술해보겠습니다:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface RunbookStep {
title: string;
description: string;
}
interface Runbook {
id: string;
title: string;
severity: Severity;
detection: string;
steps: RunbookStep[];
}
export const checkoutFailureRunbook: Runbook = {
id: 'rb-checkout-failure',
title: 'GiftGenius에서 checkout 오류 증가',
severity: 'SEV-1',
detection: '알림: checkout_success_rate < 60% (10분 기준)',
steps: [
{
title: '외부 상태 확인',
description: 'Stripe와 ACP 백엔드 상태 페이지를 열어 글로벌 장애가 없는지 확인합니다.',
},
{
title: '최근 릴리스 확인',
description: '최근 30분 동안 MCP/ACP 배포가 있었는지 확인합니다. 필요 시 롤백합니다.',
},
],
};
실제 런북에서는 더 많은 단계를 추가할 수 있습니다: read-only feature flag를 켜기, 위젯에 배너 표시, 포스트모템을 위한 로그 수집 등.
커머스 인시던트 시 위젯에 표시할 문구 예시
런북에는 사용자에게 보여줄 문구도 미리 고민해 두면 좋습니다. 예를 들어, GiftGenius 위젯은 다음을 보여줄 수 있습니다:
«현재 결제에 일시적인 기술 문제가 있습니다. 마음에 드는 선물 아이디어는 계속 저장하실 수 있으며, 결제는 조금 뒤에 완료하겠습니다.»
이런 문구는 UI 상태에 다음처럼 넣을 수 있습니다:
// 위젯 상태에 대한 의사 코드
const [checkoutAvailable, setCheckoutAvailable] = useState(true);
if (!checkoutAvailable) {
return (
<Alert>
결제가 일시적으로 불가능합니다. 선물 아이디어는 계속 탐색하고 저장하실 수 있어요.
</Alert>
);
}
6. GiftGenius에서의 실전: 인시던트 주변 코드
주제가 조직론에만 머물지 않도록, 인시던트 관리에 직접 도움이 되는 코드 조각을 몇 가지 살펴봅니다.
MCP/백엔드를 위한 Health-check 엔드포인트
가장 단순하지만 중요한 도구가 health‑check입니다. Next.js 16에서는 route handler로 만들 수 있습니다:
// app/api/health/route.ts
import { NextRequest, NextResponse } from 'next/server';
export function GET(_req: NextRequest) {
// DB, 큐 등 점검을 추가할 수 있습니다.
return NextResponse.json({
status: 'ok',
mcp: 'healthy',
timestamp: new Date().toISOString(),
});
}
모니터링 시스템은 주기적으로 /api/health를 폴링합니다. 200 OK 대신 타임아웃이나 5xx가 나오기 시작하면, 이것은 Availability 인시던트(MCP가 살아 있지 않음)의 명확한 신호입니다.
메트릭 기반 인시던트 분류
분석 서비스나 관리자 백엔드 스크립트에서 간단한 심각도 판단 로직을 둘 수 있습니다:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface IncidentContext {
checkoutSuccessRate: number; // 0..1
giftSearchErrorRate: number; // 0..1
p95GiftSearchMs: number;
}
export function classifyIncident(ctx: IncidentContext): Severity | null {
if (ctx.checkoutSuccessRate < 0.6) return 'SEV-1'; // 돈이 움직이지 않음
if (ctx.giftSearchErrorRate > 0.3 || ctx.p95GiftSearchMs > 8000) return 'SEV-2';
return null; // 아직 인시던트 아님
}
이 로직은 크론으로 실행하거나 모니터링에서 트리거할 수 있습니다. SEV‑1을 반환하면 시스템에 자동으로 인시던트를 생성하고 on-call에게 알림을 보냅니다.
인시던트의 핵심 이벤트 로깅
인시던트는 메트릭뿐 아니라 이벤트이기도 합니다: 인시던트가 생성/변경/종료된 시점. 이를 별도의 로그에 보관하면 편리합니다.
function logIncidentEvent(event: {
incidentId: string;
type: 'created' | 'mitigated' | 'resolved';
severity: Severity;
requestId?: string;
message: string;
}) {
logger.warn({
level: 'WARN',
service: 'incident-manager',
...event,
timestamp: new Date().toISOString(),
});
}
예를 들어 GiftGenius에서 “read-only” 모드를 켰을 때:
setCheckoutDisabled(true);
logIncidentEvent({
incidentId: 'inc-2025-11-21-001',
type: 'mitigated',
severity: 'SEV-1',
message: 'Checkout disabled, app switched to recommendations-only mode',
});
그 후 이런 이벤트를 쉽게 찾아 메트릭 시계열과 대조할 수 있습니다.
7. 운영 캘린더: “고쳤다!” 이후의 삶
인시던트 관리는 불 끄기만이 아니라 정기적 예방도 포함합니다. SRE 관행에서는 운영 사이클을 자주 운영 캘린더로 설명하며, 정기적인 SLO/비용/보안 리뷰를 포함합니다.
주기별로 활동을 나눌 수 있습니다.
주간
일주일(또는 격주)마다 다음을 권장합니다:
- 핵심 SLO 검토: latency, error-rate, 결제 성공, 카테고리별 인시던트 비중;
- 한 주 동안 자동으로 “자연스레 사라진” 알림이 있었는지 확인하고 임계치를 강화/완화할지 결정;
- 최소 한 건의 인시던트를 간단히 리뷰(SEV‑3라도 좋음) — 포스트모템 역량을 단련합니다.
월간
매월 다음을 권장합니다:
- 비용 리뷰(LLM, ACP/Stripe 수수료, 인프라)와 매출을 대응해 살펴보기 — 모듈 19의 1–2 주제와 연결;
- 제품 메트릭 확인: activation, retention, workflow_completed → checkout_success 전환 — 마케팅/성장 모듈과 연계;
- 보안 로그를 훑어 이상 여부 확인: 로그인 패턴 이상, 인증 오류, 비정상적인 요청 급증(보안 모듈로 이어지는 다리).
분기별
분기마다 다음을 수행합니다:
- 시크릿 로테이션: OpenAI, Stripe API 키, OAuth 클라이언트 등;
- SLO가 오래되지 않았는지 확인: App이 성장해 이제 p95 2초(이전 1초)가 정상인지, 혹은 반대로 목표를 더 엄격히 할 수 있는지;
- 런북 재검토: 새로운 인시던트 유형, 업데이트된 의존성(SDK, MCP 스펙 등).
캘린더는 GiftGenius 저장소의 Wiki 페이지나 README 형식으로 간단히 관리해도 됩니다. 중요한 것은 “살아 있는 문서”로 유지·갱신하는 것입니다.
8. 인시던트, 돈, 그리고 제품: 왜 커머스 화재가 가장 뜨거운가
모듈 19는 전반적으로 App의 경제성과 “운영의 삶”을 다루며, 여기에서 인시던트는 돈과 밀접히 연결됩니다. 결제가 진행되지 않거나, 돈이 묶이거나, 두 번 청구되는 커머스 인시던트는, 선물 검색의 가끔 있는 타임아웃보다 거의 항상 우선순위가 높습니다.
이유는 간단합니다:
- 현재 시점 매출의 직접적 손실;
- 신뢰 상실 위험(돈이 빠져나갔는데 상품을 받지 못한 사용자는 돌아오기 어렵습니다);
- 법적·평판상 파장 가능성.
따라서 GiftGenius의 인시던트 카탈로그에서는 커머스 인시던트를 명확히 SEV‑1로 표시하고, 엄격한 대응 SLO(예: “on-call 15분 내 반응, 1시간 내 완화”)를 두어야 합니다.
경제적 이상(예: 매출 증가 없이 LLM 비용이 급등)도 인시던트이지만, 보통 SEV‑2 수준입니다. 즉시 UX를 깨진 않지만, 눈치채지 못하면 마진을 “모두 먹어치울” 수 있습니다.
제품 관점에서 큰 인시던트는 다음을 고민할 기회이기도 합니다:
- 워크플로가 과도하게 복잡하지 않은가(단순함이 더 신뢰성을 높일 수 있습니다);
- 폴백 시나리오를 추가할 필요는 없는가: 예를 들어 MCP가 응답하지 않으면 모델이 외부 데이터 없이라도 조언을 제공;
- 문제를 숨기지 않고 솔직히 알리도록 UX를 바꿔야 하지 않는가.
9. 미니 실습(자기 주도형)
강의가 실습 수업은 아니지만, 여러분의 GiftGenius에서 다음 단계를 실제로 수행해 보길 강력히 권장합니다:
- 최소 두 개의 런북을 하나의 문서에 작성:
- “결제(checkout)에서 대량 오류 발생”;
- “MCP가 응답하지 않음 / ChatGPT에서 Error talking to app 표시”.
- 한 달짜리 운영 캘린더를 구성:
- 매주 확인할 SLO는 무엇인가;
- 월말에 어떤 비용 리뷰를 할 것인가;
- 어떤 보안 점검을 포함할 것인가(기본적인 것이라도).
몇 시간 투자로, 여러분의 앱을 바라보는 방식이 크게 달라질 것입니다. 단순한 코드가 아닌 살아 있는 서비스가 됩니다.
ChatGPT Apps의 인시던트 관리에서 흔한 실수
오류 №1: “인시던트는 전부 다운될 때만이다”
많은 이들이 MCP나 데이터베이스의 완전 다운만 인시던트로 간주하는 경향이 있습니다. AI‑App에서는 필요한 tool 호출이 멈추거나, checkout 플로우가 혼란스러워지거나, HTTP 메트릭이 초록불이어도 사용자가 끝까지 도달하지 못하는 등 “부드러운” 품질 인시던트가 더 아플 때가 많습니다. 이런 상황을 인시던트로 보지 않고 분석하지 않으면, App의 품질은 눈에 띄지 않게 악화됩니다.
오류 №2: 명확한 SLO와 “정상 동작” 경계의 부재
공식 SLO가 없으면, 인시던트에 대한 모든 논의는 “느린 것 같다” vs “내 로컬에서는 빠르다”로 변합니다. 그렇기에 SLO는 인시던트 관리의 기반입니다. 문제의 심각도를 객관화해 줍니다.
오류 №3: 런북 대신 즉흥 대응
흔한 장면: 알림이 오면 모두가 패닉 상태로 프로덕션에 뛰어들고, 누군가는 릴리스를 롤백하고, 누군가는 설정을 고치고, 한 시간 뒤 “아마 고친 듯” 하지만 무엇이 효과를 냈는지 아무도 기억하지 못합니다. 런북이 없으면 매 인시던트가 작은 혼돈이며 팀은 학습하지 못합니다. checkout 인시던트에 대한 간단한 런북 하나만으로도 스트레스를 크게 낮출 수 있습니다.
오류 №4: 사용자 커뮤니케이션 무시
가끔 엔지니어가 조용히 시스템을 고치는 동안, 사용자는 “로딩 스피너”와 “문제가 발생했습니다”만 보게 됩니다. 커머스 시나리오에서는 특히 독합니다. 사람들은 돈 문제에 민감합니다. 위젯, App 설명, 필요 시 외부 채널에 상황과 예상 복구 시간을 솔직하게 알릴 메시지 템플릿을 미리 준비하는 것이 중요합니다.
오류 №5: 자체 분석 없이 “OpenAI 탓”만 하기
모든 것을 “OpenAI가 불안정해서”로 돌리기 쉽지만, upstream 문제일 때도 우리 쪽에서 할 수 있는 것이 많습니다: 타임아웃과 오류를 올바르게 처리하고, MCP 없이 동작하는 모드로 전환하고, 재시도 횟수를 줄여 사태를 악화시키지 않는 등. 공유 책임(shared responsibility) 개념은, 제공자 중 하나가 불안정하더라도 여러분이 체인의 자신의 부분에 책임을 진다는 뜻입니다.
오류 №6: 포스트모템과 운영 사이클의 부재
인시던트가 “대충 끝났으니 계속 가자”로 마무리되고, 문서·알림·코드가 아무것도 바뀌지 않는다면, 시스템은 같은 실수를 반복할 수밖에 없습니다. 포스트모템, 정기 SLO/비용/보안 리뷰는 관료주의가 아니라, 1년 뒤 더 탄탄한 GiftGenius를 위해 미래의 나와 팀과 약속을 만드는 방법입니다.
GO TO FULL VERSION