f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.6 KiB
5.6 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-error-handling-and-stability | Error Handling and Stability | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
Error Handling and Stability
매 한 줄
"매 frontend stability = error 의 isolation + telemetry + graceful degradation.". 매 single uncaught error가 매 SPA 의 전체 white-screen 의 유발 — 매 ErrorBoundary, global handlers (
window.onerror,unhandledrejection), 매 Sentry-class telemetry 가 필수. 매 2026의 트렌드는 React 19 ErrorBoundary + Sentry + Replay + AI-driven root-cause clustering.
매 핵심
매 layers
- Component: React ErrorBoundary, Vue
errorCaptured, Svelte<svelte:boundary>. - Async: try/catch, Promise
.catch,unhandledrejectionlistener. - Global:
window.onerror,window.onunhandledrejection. - Network: fetch retry, circuit breaker, AbortController.
매 telemetry 기둥
- Capture (stack, breadcrumb, source map).
- Group (fingerprint, dedup).
- Alert (threshold, regression).
- Replay (Sentry / LogRocket — DOM reconstruction).
매 응용
- SPA route-level boundary — 매 chunk load fail 의 reload prompt.
- Form submission retry with exponential backoff.
- Feature flag fallback when remote config unavailable.
- Service Worker offline shell.
💻 패턴
1. React ErrorBoundary (class)
import { Component, type ReactNode } from 'react';
interface State { error?: Error }
export class ErrorBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, State> {
state: State = {};
static getDerivedStateFromError(error: Error): State { return { error }; }
componentDidCatch(error: Error, info: React.ErrorInfo) {
Sentry.captureException(error, { extra: { componentStack: info.componentStack } });
}
render() {
return this.state.error ? this.props.fallback : this.props.children;
}
}
2. react-error-boundary (functional)
import { ErrorBoundary } from 'react-error-boundary';
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<div role="alert">
<p>Failed: {error.message}</p>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
)}
onReset={() => location.reload()}
>
<App />
</ErrorBoundary>
3. Global handlers
window.addEventListener('error', (e) => {
Sentry.captureException(e.error ?? new Error(e.message));
});
window.addEventListener('unhandledrejection', (e) => {
Sentry.captureException(e.reason);
});
4. Chunk load failure recovery
const lazyWithRetry = <T,>(load: () => Promise<{ default: T }>) =>
React.lazy(async () => {
try {
return await load();
} catch (err) {
if (!sessionStorage.getItem('chunk-retried')) {
sessionStorage.setItem('chunk-retried', '1');
location.reload();
}
throw err;
}
});
5. Fetch retry with backoff
async function fetchRetry(url: string, retries = 3, delay = 500): Promise<Response> {
try {
const res = await fetch(url);
if (!res.ok && res.status >= 500) throw new Error(`HTTP ${res.status}`);
return res;
} catch (err) {
if (retries === 0) throw err;
await new Promise((r) => setTimeout(r, delay));
return fetchRetry(url, retries - 1, delay * 2);
}
}
6. AbortController on unmount
useEffect(() => {
const ac = new AbortController();
fetch('/api/x', { signal: ac.signal }).catch((e) => {
if (e.name !== 'AbortError') report(e);
});
return () => ac.abort();
}, []);
7. Sentry init (2026)
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration({ maskAllText: false }),
],
tracesSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
release: import.meta.env.VITE_RELEASE,
});
8. Vue 3 errorHandler
import { createApp } from 'vue';
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
Sentry.captureException(err, { extra: { info } });
};
매 결정 기준
| 상황 | Approach |
|---|---|
| Component-local fail | ErrorBoundary at route level. |
| Async fail | try/catch + telemetry. |
| Chunk 404 (deploy mid-session) | lazyWithRetry + reload. |
| Transient 5xx | Exponential backoff retry. |
| Auth expired | Refresh token interceptor. |
기본값: Sentry + Replay + per-route ErrorBoundary + global handlers.
🔗 Graph
- 부모: Observability
- 변형: Circuit Breaker
- 응용: Sentry · Logrocket
- Adjacent: Source Maps · Feature Flags
🤖 LLM 활용
언제: ErrorBoundary scaffolding, retry helper 작성, Sentry config. 언제 X: 매 root-cause analysis from minified stack — 매 source map upload 필수.
❌ 안티패턴
- Swallow errors: 매
catch {}빈 — 매 silent fail. - No source map: 매 prod stack 의
a.b.c— 매 debug X. - Boundary at root only: 매 한 component fail이 매 entire app crash.
- Console.error as monitoring: 매 user 의 console 의 도달 X — telemetry 필수.
🧪 검증 / 중복
- Verified (Sentry docs, react.dev error boundary).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Error boundary + Sentry 2026 patterns |