ClOr

ClOr

백엔드 실무 트러블슈팅과 AI 에이전트 구조 분석을 기록합니다.

Claude Code 해부학 (완결)

51만 줄 소스코드를 19편에 걸쳐 분석한 완결 시리즈

전체 시리즈 보기 →

백엔드 트러블슈팅

실무에서 겪은 장애와 해결 과정 기록

전체 시리즈 보기 →

최신 글

article thumbnail

들어가며

사이드 프로젝트 Shift(shift-dev.kr)를 운영하면서, 배포할 때마다 서비스가 수십 초간 중단되는 문제가 있었다. 실사용자 500명이 쓰는 서비스에서 이건 용납할 수 없었다.

Windows self-hosted runner + NSSM + Caddy 조합으로 Blue-Green 무중단 배포를 구축했는데, 기본 구조는 하루면 만들었지만 안정화에 50개 이상의 커밋이 들었다.

환경

  • Windows 10 + GitHub Actions self-hosted runner
  • Java 25 + Spring Boot 4 (백엔드)
  • SvelteKit + Svelte 5 (프론트엔드)
  • Caddy (리버스 프록시) + NSSM (Windows 서비스 관리)


기본 구조

                    ┌─ :8080 (Blue)  ← 현재 활성
사용자 → Caddy ────┤
                    └─ :8081 (Green) ← 대기
  1. Green(8081)에 새 버전 배포
  2. 헬스체크 통과 → Caddy가 Green으로 트래픽 전환
  3. Blue(8080)가 대기 상태로 전환
  4. 다음 배포 시 역할 교대

50커밋의 엣지 케이스들

# 문제 원인 해결
1 NSSM "marked for deletion" SCM이 핸들 해제 전 재등록 시도 서비스 완전 삭제까지 폴링 대기
2 SERVICE_PAUSED 상태 시작도 중지도 안 되는 과도 상태 continue → stop → start 강제 복구
3 stderr → step 실패 PowerShell stderr를 Actions가 실패로 처리 $ErrorActionPreference = "Continue"
4 Workspace 파일 락 이전 Java 프로세스가 jar를 물고 있음 shallow clone + 프로세스 확실 종료
5 Gradle 데몬 OOM 빌드 반복으로 메모리 누적 ./gradlew --stop + Xmx 설정
6 SvelteKit 빌드 메모리 Node 힙 부족 NODE_OPTIONS=--max-old-space-size=4096

문제 1: NSSM 서비스 삭제 대기

nssm stop $serviceName
nssm remove $serviceName confirm
while (Get-Service $serviceName -ErrorAction SilentlyContinue) {
    Start-Sleep -Seconds 1  # ← 완전히 사라질 때까지 대기
}
nssm install $serviceName ...

문제 4: Workspace 파일 락

git fetch --depth=1 origin $branch
git reset --hard FETCH_HEAD  # ← shallow clone으로 전환

런칭 후 실서비스 이슈

배포 인프라 외에도 실사용자가 생기면서 새로운 이슈가 연이어 터졌다.

인앱 브라우저 Google OAuth 차단

카카오톡/인스타그램에서 링크를 열면 인앱 브라우저에서 열리는데, Google이 OAuth를 차단한다. 안내 UI → iframe → location.href 등 5개 커밋에 걸쳐 시행착오 끝에 인앱 브라우저 감지 → 외부 브라우저 자동 유도로 해결.

인메모리 랭킹 데이터 유실

"배포하면 인기글이 사라져요"

Hot Ranking을 인메모리로 관리했더니, Blue-Green 배포(= 프로세스 교체)할 때마다 데이터가 날아갔다. DB에 주기적으로 스냅샷을 저장하는 HotRankingSnapshotHelper를 구현하여 해결.


최종 배포 흐름

  1. 비활성 슬롯 준비 (기존 서비스 제거, 산출물 복사)
  2. NSSM 서비스 기동 (Backend + Frontend 등록, 시작)
  3. 헬스체크 (HTTP 200 확인, 3초 간격)
  4. Caddy 트래픽 전환 (caddy reload)
  5. 구 슬롯 정리 (이전 서비스 중지, 포트 갱신)
  6. 실패 시 → 신규 서비스 중지, Caddyfile 백업 복원 (자동 롤백)

결과

지표 Before After
다운타임 수십 초 제로
안정화 커밋 50+
롤백 수동 Caddy 설정 되돌리면 즉시

배운 점

  1. 무중단 배포는 "구현"이 아니라 "안정화"가 진짜 작업이다 — 기본 구조는 하루, 엣지 케이스 해결에 50커밋
  2. Windows 환경의 서비스 관리는 Linux보다 훨씬 까다롭다 — NSSM의 상태 머신을 이해하지 않으면 디버깅이 불가능하다
  3. "만드는 것"과 "운영하는 것"은 완전히 다른 영역이다 — 실사용자가 있는 서비스를 운영하면서 비로소 체감했다
profile

ClOr

@ClOr

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

ClOr · 백엔드 트러블슈팅과 AI 에이전트 구조 분석을 기록합니다.