사내 버셀의 Python 기능들은 독립된 프로세스로 실행돼 관리가 어려웠습니다. 관리할 프로세스를 줄이기 위해 Spring 단일 애플리케이션으로 통합하기로 했습니다.
팀에서 사용하는 LGTM 연동과 로그 설정도 Spring Boot를 기준으로 구성돼 있었습니다. Python을 유지하면 모니터링과 로그 연동을 별도로 구현하고 관리해야 했습니다.
| 구성 | 이점 | 추가 작업 |
|---|---|---|
| Python 유지 | 기존 구현 유지 | 모니터링과 로그 연동의 별도 구현과 유지보수 |
| Spring 통합 | 팀 공통 설정 재사용, 프로세스 통합 | 기능 이식과 기존 동작의 호환성 검증 |
기능을 이식하는 비용은 있지만, 팀 공통 설정을 재사용하고 관리할 프로세스를 줄이기 위해 Spring을 선택했습니다.
팀 공통 설정 재사용하기
우리 팀은 공통 가이드를 주제별 문서로 관리하고, Codex와 Claude Code용 플러그인으로 제공합니다. 에이전트 지침과 문서 검색 인덱스를 함께 두어 필요한 설정과 절차를 찾아 적용할 수 있도록 구성했습니다.
skills/altools-guideline/
├── SKILL.md # 에이전트 지침
├── TAGS.md # 문서 검색 인덱스
└── docs/
├── api/ # API 컨벤션
├── development/ # 개발 규칙과 코드 리뷰
├── deployment/ # 배포 절차
├── infrastructure/ # 서버와 LGTM 설정
└── onboarding/ # 온보딩 안내
프로젝트별 환경과 공통 규칙의 예외는 각 저장소의 ALTOOLS.md에 기록합니다. Codex와 Claude Code가 같은 프로젝트 문서를 참고하도록 AGENTS.md와 CLAUDE.md에서 연결합니다.
프로젝트 저장소/
├── ALTOOLS.md # 프로젝트별 환경과 규칙
├── AGENTS.md # Codex: @ALTOOLS.md 참조
└── CLAUDE.md # Claude Code: @ALTOOLS.md 참조
이렇게 공통 설정은 가이드에, 프로젝트별 차이는 ALTOOLS.md에 두고 에이전트가 두 문서를 함께 참고하도록 했습니다.
모니터링 가이드에는 Spring Boot 의존성, 메트릭과 트레이스의 OTLP 전송 설정, Logback을 통한 로그 수집과 연동 확인 절차를 정리했습니다. 사내 버셀에도 이 가이드를 적용하면 기존 설정과 점검 절차를 재사용할 수 있습니다.
Control API부터 단계적으로 전환하기
Control API 전환 과정
기존 프리뷰 서비스를 유지한 채 Control API를 Spring Boot로 교체했습니다.
전체 전환 완료 후 구조
전체 전환이 완료되면 서비스별로 실행하던 Python 프로세스를 하나의 Spring 프로세스로 통합합니다.
재배포 시 작업 보존
재배포 중에도 작업을 보존하도록 배포 요청 수신과 실행을 분리하고, 복구에 필요한 정보는 PostgreSQL에 저장합니다. 이 구조는 단계별 교체와 최종 통합 구조에서도 유지합니다.
Worker는 실행 중 heartbeat로 처리 권한을 갱신합니다. 이 동작은 기존 작업 보존 구조에서도 사용했습니다. 복구에 필요한 정보를 애플리케이션 메모리에만 두지 않는 것이 stateless를 유지하기 위한 조건입니다.
마이그레이션 시 로그인 세션 끊기는 문제 해결
Spring Security OAuth2 Client로 로그인 처리를 간소화하면서 기존 사용자의 로그인 상태도 유지해야 했습니다. 처음에는 Spring Session으로 이관하려 했지만, 새 테이블에 맞춘 호환 처리와 롤백을 위한 이중 쓰기까지 고려해야 했습니다. 그래서 기존 쿠키와 세션 테이블을 그대로 공유하는 방식으로 설계를 변경했습니다.
참고한 전환 사례
올리브영의 무중단 OAuth2 전환기에서 세 가지를 참고했습니다.
- 기존 인증 유지: 기존 세션으로 인증하면서 새 토큰을 미리 발급했습니다.
- 점진적 전환과 롤백: Feature Flag로 적용 대상을 확대하고 기존 인증으로 돌아갈 수 있도록 했습니다.
- 전환 전후 관찰: 인증 방식별 트래픽, 오류율과 응답시간을 비교했습니다.
GitHub 장애로 로그인이 끊기는 문제
GitHub 장애로 토큰 갱신에 실패하면 access token 만료 후 900초까지 기존 토큰을 보존합니다. Spring에서도 이 정책을 유지하기로 했습니다. 유예 중에는 stale 배너로 갱신 지연을 알리고 등록 해제를 막습니다. 일시적 장애와 갱신 거부는 구분하며, 갱신이 거부되면 세션을 폐기합니다.
900초는 실측 전 정한 임시값입니다. GitHub 상태 API의 “API Requests” 장애 지속 시간을 집계해 중앙값을 제시한 공식 자료는 확인하지 못했습니다.
토큰 갱신 실패부터 복구까지 걸린 시간과 유예 적용 시간을 메트릭으로 관찰할 계획입니다. 관측 결과를 바탕으로 필요한 유예만 남겨, access token 만료 후 로그인 유지 시간을 줄이고 보안을 강화하려고 합니다.
회고
처음에는 빠르게 개발하기 위해 Python을 선택했습니다. 사내 서비스로 적용하려니 팀 공통 인프라 설정에 맞추는 작업이 추가로 필요했습니다. 공통 설정과 다른 운영 사례를 남기고 싶지 않아 Python 구성으로 서비스를 더 추가하지 않기로 했습니다.
Spring으로 전환하면서 기존 기능을 이식하고 호환성을 확인하는 만큼 작업량도 늘었습니다. 다음 PoC에서는 개발 속도와 함께 사내 적용 가능성, 팀 공통 인프라 설정에 맞추는 비용도 기술 선택 단계에서 고려하려고 합니다.