결제 도메인 신규 기능에 전역 타임아웃 설정 추가
목차
결제 도메인에 신규 기능을 붙이면서 config 영역에 MVC async timeout을 전역으로 30분 박았다. 변경된 파일은 설정·문서 4개, yml_local.yml 1개, yml_prod.yml 1개. 숫자만 보면 별거 아닌 것 같지만 이 설정 하나가 빠져 있으면 기능이 중간에 끊기거나, 클라이언트 쪽에서 이유도 모른 채 504를 받는다.
왜 전역 타임아웃이 필요했나
기존 화면·API가 제공하지 않던 데이터와 동작을 결제 도메인에 새로 올려야 했다. 단순 UI 추가가 아니라 쿼리 레벨부터 설계해서 정합성을 맞추는 방식으로 진행했는데, 문제는 이번 경로가 응답 시간이 늘어날 수 있는 구조였다는 거다.
Spring MVC에서 비동기 처리를 쓸 때 async timeout은 서버 설정에 따라 달라진다. Tomcat 기본값은 10초, 애플리케이션 레벨 설정이 없으면 컨테이너 값을 그대로 따른다. 결제 도메인 특성상 외부 시스템 연동이나 집계 쿼리가 포함되는 경우엔 이 값이 실제로 걸린다. 이미 운영 중인 다른 화면에서 타임아웃 이슈가 없었던 건, 그쪽이 애초에 동기 방식이거나 응답이 빠른 단건 조회였기 때문이다. 이번엔 async로 처리해야 했고, 전역 설정이 없는 채로 배포하면 어떤 환경에서 어떤 값이 적용되는지 예측이 안 됐다.
그래서 설정 파일에 명시적으로 박았다. 30분으로 잡은 건 "이 이상 걸리면 어차피 뭔가 잘못된 거다"라는 실용적 판단이다. 무한대로 두면 장애 상황에서 커넥션이 물고 늘어지고, 너무 짧으면 정상 처리도 끊긴다. 타임아웃은 "이상 케이스를 내가 죽인다"는 안전망이지, 느린 쿼리를 감추는 도구가 아니다.
# application-local.yml / application-prod.yml
spring:
mvc:
async:
request-timeout: 1800000 # 30분, ms 단위
local과 prod 양쪽을 별도 파일로 관리하는 구조라 두 파일 모두 명시적으로 썼다. 한 쪽만 적어두면 나중에 "왜 prod에서만 끊기지?"라는 상황이 생긴다. 환경별로 값을 다르게 가져가야 하는 순간이 오더라도 이 구조면 오버라이드가 깔끔하다.
구현 흐름과 설계 판단
기능 자체는 관련 내부 클래스에 메서드를 추가하고, SQL 매퍼에 쿼리를 붙이고, 화면 렌더링까지 연결하는 수직 슬라이스 방식으로 진행했다. 기존 로직과 충돌 여부를 사전에 확인하는 게 가장 먼저였다.
결제 도메인에서 새 쿼리를 짤 때 실행 계획을 먼저 보는 건 루틴이 됐다. 집계가 들어가면 인덱스를 타는지, 풀스캔이 발생하는지 확인한다. 조회가 느리면 타임아웃을 30분으로 늘려봐야 근본 해결이 아니다. 실행 계획이 이상하면 타임아웃 설정보다 먼저 쿼리를 손봐야 한다.
| 항목 | 결정 | 이유 |
|---|---|---|
| 실시간 갱신 방식 | 요청 시 조회, 폴링 제외 | 결제 이력 특성상 실시간성보다 정확성 우선 |
| NULL·빈 데이터 처리 | 방어적 처리, 기본값 반환 | 권한 없는 접근, 빈 집계 케이스 존재 |
| 기존 로직 충돌 확인 | 화면 간 cross-check 필수 | 같은 집계 값이 여러 화면에 노출됨 |
| async timeout | 전역 30분 고정 | 이 이상이면 비정상 케이스로 분류 |
데이터 정합성 부분이 이번 작업에서 제일 신경 쓰인 대목이었다. 금융·결제 도메인에서 숫자 하나가 다르면 신뢰 문제로 바로 이어진다. "대충 맞는 것 같다"는 판단은 나중에 반드시 돌아온다. 같은 집계 값을 표시하는 화면이 여러 군데 있었고, 한 화면에서만 확인하면 놓치는 케이스가 생긴다. 구현 후 직접 화면에서 동작을 확인했고, 관련 화면들 사이에서 숫자가 일치하는지 전부 맞춰봤다.
예외 케이스 방어 순서도 정해두고 진행했다.
- NULL이 올 수 있는 컬럼은 집계 전에 COALESCE 처리
- 권한 없는 접근은 서비스 레이어에서 먼저 막고, 쿼리까지 내려가지 않게
- 빈 결과 집합이 돌아왔을 때 화면에 이상한 값 대신 의미 있는 기본 상태를 보여줄 것
- async 요청이 타임아웃 전에 정상 종료되는 케이스와, 실제 타임아웃으로 끊기는 케이스를 시나리오로 구분해서 확인
작업 후기
사내 서비스를 계속 만들다 보면 기능 하나가 단순히 버튼 하나 추가로 끝나지 않는다는 걸 반복해서 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크, 그리고 이번엔 async timeout 설정까지. 어느 하나만 빠뜨려도 숫자가 안 맞거나 특정 사용자에게 이상한 화면이 나온다.
이번에 배운 게 하나 있다면, async 처리를 도입할 때 타임아웃 설정을 명시적으로 박는 걸 습관으로 만들어야 한다는 거다. "기본값이 있겠지"라고 믿으면 환경마다 다른 동작을 나중에 디버깅하게 된다. 특히 local/prod를 별도 yml로 관리하는 구조에서는 양쪽 다 써줘야 나중에 헷갈리지 않는다. 설정 누락은 코드 버그보다 찾기 어려운 케이스가 많다.
커밋 단위도 이번에 의식적으로 쪼갰다. 설정 변경과 기능 변경이 같은 커밋에 들어가면, 나중에 어느 시점에 어떤 이유로 타임아웃 값이 바뀐 건지 추적하기 어렵다. 작은 커밋을 자주 하면 문제가 생겼을 때 원인 찾는 시간이 확 줄어든다. 논리적으로 독립된 단위로 쪼개는 습관을 계속 유지 중이다.
커밋 메시지도 "무엇을"보다 "왜"를 담으려고 한다. 30분이라는 숫자만 남기면 반년 뒤에 이게 왜 30분인지 아무도 모른다. 당시 판단 근거를 한 줄이라도 남겨두면 나중에 값을 바꿔야 할 때 기준이 생긴다.
개발 루틴으로는 변경 전 현재 동작 수치나 스크린샷을 메모하고, 수정 후 같은 케이스로 재확인하는 걸 유지 중이다. 귀찮아 보이지만 이게 없으면 "원래 이랬나?"를 기억에 의존해야 한다. 금융 도메인에서 기억을 믿는 건 위험하다.
댓글 0
첫 댓글 달아줘.