프로그래머스 검색 장애 수정 — Dockerfile data/ 번들 누락
Sprint 98 — 프로그래머스 검색 장애 수정
배경
Sprint 95~97에서 프로그래머스 전환을 완료하였으나, 운영 환경에서 프로그래머스 문제 검색이 전면 NotFoundException 을 반환하는 장애가 발생했다. 서비스 자체 로직은 정상이었고, 원인은 인프라 (Dockerfile) 계층의 파일 번들 누락이었다.
증상
GET /external/programmers/search?q=모의고사→404 NotFoundException- Gateway 서비스 로그:
프로그래머스 JSON 로드 실패 (빈 캐시로 기동): Error: ENOENT: no such file or directory - 부팅 시
cache.size = 0→ 모든 검색/조회 불가
근본 원인 분석
경로 추적
CMD: node dist/src/main.js
컴파일 위치: src/external/programmers.service.ts → dist/src/external/programmers.service.js
__dirname @ runtime: /app/dist/src/external/
join(__dirname, '..', '..', 'data', 'programmers-problems.json')
= /app/dist/src/external/../../data/programmers-problems.json
= /app/dist/data/programmers-problems.json ← 컨테이너 내 기대 경로
Dockerfile 분석
# production stage (수정 전)
COPY --from=builder /app/dist ./dist # dist/ 복사
# data/ 미포함 → /app/dist/data/ 존재하지 않음
- Builder 단계:
COPY . .로data/programmers-problems.json존재 (/app/data/) npm run build(nest build):data/→dist/자동 복사 없음- Production stage:
dist/만 복사,data/누락 - 결과:
/app/dist/data/programmers-problems.json미존재 → ENOENT → 빈 캐시
ts-node 환경과의 차이
로컬 개발(nest start:dev, ts-node) 환경에서는 __dirname = /app/src/external/ 이므로
join('..', '..', 'data') = /app/data/ (프로젝트 루트) → 파일 존재하여 정상 작동.
컴파일 환경에서만 경로가 dist/ 기준으로 이동하므로 개발 중 재현 불가했던 이유다.
수정 내용
1. nest-cli.json — assets 자동 번들 (NestJS 관례)
"compilerOptions": {
"deleteOutDir": true,
"assets": [
{
"include": "../data/**",
"outDir": "./dist/data",
"watchAssets": false
}
]
}
npm run build 실행 시 data/ → dist/data/ 자동 복사. 로컬 컴파일 빌드에서도 재현 방지.
2. Dockerfile — 명시적 COPY (안전망)
COPY --from=builder /app/data ./dist/data
nest-cli assets 경로 해석의 버전 의존성과 무관하게, 반드시 /app/dist/data/에 파일이 존재함을
보장하는 안전망. CI 빌드 시 이 레이어가 없으면 이미지 빌드 실패로 조기 발견 가능.
수정된 파일
| 파일 | 작업 | 설명 |
|---|---|---|
services/gateway/Dockerfile | 수정 | production stage에 COPY --from=builder /app/data ./dist/data 추가 |
services/gateway/nest-cli.json | 수정 | compilerOptions.assets 추가로 nest build 시 자동 복사 |
검증 결과
단위 테스트
Test Suites: 50 passed, 50 total
Tests: 754 passed, 754 total (programmers 관련 43건 포함)
programmers.service.spec.ts: 기존loadFromFile→fetchProblem성공 검증으로 충분cache.size > 0검증은fetchProblem(42840)성공으로 동치 → 신규 테스트 불필요
E2E 테스트 (programmers-full-flow.spec.ts)
Test Suites: 1 passed, 1 total
Tests: 13 passed, 13 total
[A] GitHub Worker 파일 경로 생성 — 4건 PASS
[B] MQ 이벤트 계약 sourcePlatform 검증 — 4건 PASS
[C] AI 프롬프트 플랫폼 맥락 주입 — 3건 PASS (Python 3.9.6 로컬: empty-pass, CI Python 3.12에서 완전 실행)
[D] 외부 API 격리 검증 — 2건 PASS
타입/린트
tsc --noEmit: PASS (오류 없음)
eslint: 0 errors, 6 warnings (pre-existing, programmers 수정과 무관)
- structured-logger.service.ts: _t, _r unused vars
- public-profile.controller.spec.ts, public-share.controller.spec.ts: fetch/모킹 unused vars
회귀 방지
- Dockerfile 안전망:
COPY --from=builder /app/data ./dist/data레이어로 빌드 시 data/ 존재 보장 - nest-cli.json assets:
npm run build로컬 환경에서도dist/data/자동 생성 - CI 검증 권장 (이월):
.github/workflows/에dist/data/programmers-problems.json존재 검증 step 추가
2차 증상 — 레벨 0 문제 미크롤링
증상
Dockerfile 수정 후에도 프로그래머스 레벨 0(코딩기초트레이닝) 문제를 검색하면 404 NotFoundException.
원인
크롤러 services/gateway/scripts/fetch-programmers-problems.ts:55 의 LEVELS = [1, 2, 3, 4, 5] 상수가 레벨 0을 명시적으로 제외하여 JSON 스냅샷(373건)에 코딩기초트레이닝 문제가 전혀 포함되지 않음.
수정 내용
- 크롤러
LEVELS확장 —[0, 1, 2, 3, 4, 5]로 변경 (커밋266c8c5) levelToDifficulty(0)— 기존?? null분기가 이미 레벨 0을null매핑으로 처리 → 로직 변경 없이 주석만0~5범위로 갱신- 회귀 테스트 —
programmers.service.spec.ts에 레벨 0 봉투 형식 로드 +difficulty=null검증 1건 추가 (총 44건 PASS) - 운영 반영 — 코드 수정 후 데이터 재수집 필요:
cd services/gateway && npm run fetch-programmers(Playwright 네트워크 작업, 수 분 소요)
검증 결과
programmers.*.spec.ts: 44건 PASS (+1건 신규)tsc --noEmit: PASS
데이터 재수집 완료 (커밋 1bc2a0a)
npm run fetch-programmers 실행 결과:
| 레벨 | 건수 | 비고 |
|---|---|---|
| Lv0 (코딩기초트레이닝) | 240 | 신규 |
| Lv1 | 95 | 기존 |
| Lv2 | 132 | 기존 |
| Lv3 | 95 | 기존 |
| Lv4 | 31 | 기존 |
| Lv5 | 20 | 기존 |
| 총계 | 613 (+240) | 373 → 613 |
- 버전:
2026-04-20T04:35:10.312Z - Zod 검증 PASS
- 샘플: 120583 "중복된 숫자 개수", 120585 "머쓱이보다 키 큰 사람", 120802 "두 수의 합 구하기"
- 검증 문제
42840 모의고사존재 확인 - 소요 시간: 70초 (단일 패스)
3차 보강 — Dockerfile 빌드시점 검증 (커밋 cfb19ec)
COPY --from=builder /app/data ./dist/data 직후 RUN test -f /app/dist/data/programmers-problems.json 추가.
향후 경로 변경/삭제 시 docker build 자체가 실패하여 조기 발견. CI에 별도 step 추가 불필요한 inline 방어.
이월 항목
| # | 항목 | 우선순위 |
|---|---|---|
| 1 | 레벨 0 문제 tags 보강 — fetch-programmers-tags.ts 2차 패스 실행 (240건 태그 빈 배열) | 보통 |
| 2 | H5 UX 개선 — 키워드 검색 연동 (프론트 검색창 → Gateway searchByQuery API 호출) | 낮음 |
| 3 | ESLint pre-existing 경고 6건 정리 (structured-logger, public-profile/share spec) | 낮음 |
커밋
| SHA | 메시지 |
|---|---|
79b6dbb | fix(gateway): Dockerfile에 programmers JSON 데이터 번들 추가 |
bf794a5 | docs(adr): Sprint 98 — 프로그래머스 검색 장애 수정 기록 |
b84c481 | docs(adr): Sprint 98 — Postman 검증 결과 보완 |
266c8c5 | fix(gateway): 프로그래머스 레벨 0 문제 크롤링 대상 포함 |
9e78e19 | docs(adr): 레벨 0 크롤링 누락 2차 증상 기록 |
1bc2a0a | chore(data): 프로그래머스 문제 레벨 0 포함 재수집 (373 → 613건) |
cfb19ec | fix(gateway): Dockerfile 빌드시점 data/ 번들 누락 검증 추가 |