타임아웃 계산과 시스템별 기능 처리 로직 개선
목차
타임아웃 계산 방식과 시스템별 Feature 처리 로직을 손댄 작업이었다. 커밋 규모 자체는 크지 않았는데, 운영 중 발견된 개선 포인트를 바탕으로 한 수정이라 실제로 챙겨야 할 포인트가 생각보다 많았다.
Spring MVC + MyBatis 구조에서 내부 클래스가 요청 처리와 화면 제어를 담당하고, SQL은 XML로 분리해서 관리한다. 레이어가 명확하게 나뉘어 있어 수정 범위를 추적하기 좋은 편이지만, 그 명확함 때문에 변경 하나가 컨트롤러-서비스-DAO-SQL-JSP 전 레이어를 타고 파급효과를 내기도 한다. "작은 수정"이라고 방심하다가 기존 흐름에 구멍이 생기는 케이스는 시스템이 좀 된 레거시 코드베이스에서 의외로 자주 나온다.
타임아웃 계산 - 왜 틀리기 쉬운가
타임아웃 관련 로직은 평소에 건드릴 일이 없다가, 운영에서 한 번 터지면 원인 파악이 까다롭다. 값이 잘못 계산되더라도 대부분의 경우 정상 응답처럼 내려오고, 특정 조건(부하, 특정 입력값 조합)에서만 증상이 나타나는 경우가 많기 때문이다.
이번에 손댄 부분은 시스템별로 분기되는 Feature 처리 로직과 맞물려 있었다. 시스템마다 허용하는 기능 범위가 다른데, 타임아웃 계산이 그 분기를 제대로 타지 못하면 어떤 시스템에서는 너무 짧게, 어떤 시스템에서는 너무 길게 잡히게 된다. 실사용자 흐름에서 발견된 케이스였다.
// 개선 전 - 시스템 구분 없이 공통 타임아웃 적용
int timeout = DEFAULT_TIMEOUT;
// 개선 후 - 시스템별 Feature 설정을 반영한 계산
int timeout = featureConfig.isEnabled(systemCode, FEATURE_X)
? featureConfig.getTimeout(systemCode)
: DEFAULT_TIMEOUT;
단순해 보이는 변경인데, 핵심은 featureConfig에서 값을 읽는 타이밍과 systemCode가 올바르게 바인딩되어 있는지였다. 요청 파라미터 검증 단계에서 systemCode를 제대로 파싱하지 않으면 뒤 로직이 전부 기본값으로 떨어진다. 그래서 바인딩 처리를 먼저 점검했다.
개발하면서 결정해야 했던 것들
트랜잭션 범위는 이번에도 한 번 짚고 넘어갔다. DB를 건드리는 로직에 @Transactional 범위를 어떻게 잡느냐는 생각보다 자주 애매해진다. 특히 Feature 조회(읽기)와 상태 업데이트(쓰기)가 같은 흐름 안에 섞일 때는 범위를 넓게 잡으면 불필요한 락이 생기고, 좁게 잡으면 중간에 실패했을 때 정합성이 깨질 수 있다. 이번 케이스에서는 쓰기가 포함된 구간만 트랜잭션으로 감쌌다.
예외 처리 방향도 결정이 필요했다. RuntimeException을 그대로 전파할지, 잡아서 응답 형태로 변환할지. 내부 로직에서 발생한 예외를 상위로 그냥 올리면 공통 핸들러가 처리하지만, 그러면 어떤 레이어에서 터진 건지 로그가 뭉개지는 경우가 있다. 이번에는 비즈니스 예외는 잡아서 응답 변환, 예상치 못한 예외는 전파하는 방향으로 정리했다.
| 예외 유형 | 처리 방식 | 이유 |
|---|---|---|
| 파라미터 검증 실패 | 잡아서 응답 변환 | 클라이언트가 수정 가능한 오류 |
| Feature 조회 실패 | 기본값으로 폴백 | 가용성 우선, 기능 제한으로 대응 |
| DB 예외 | 전파 | 공통 핸들러에서 알람 연동 |
로그는 운영에서 디버깅 가능한 수준으로 남겨두는 게 목표였다. 타임아웃 계산 결과, 사용된 systemCode, Feature 활성화 여부 정도는 INFO로 남겼다. 과하면 로그 볼륨이 문제가 되지만, 이 정도 정보가 없으면 운영 이슈 생겼을 때 맥락을 잡기가 어렵다.
log.info("[FeatureTimeout] systemCode={}, featureEnabled={}, appliedTimeout={}ms",
systemCode, featureEnabled, timeout);
이런 수정을 안전하게 배포하는 방법
로컬에서 기동 확인 후 개발 DB에 반영하고, 그다음 배포 순서로 처리했다. 타임아웃 관련 변경은 특히 실제 환경에서 동작을 확인하는 게 중요하다. 로컬에서는 응답이 즉각적이라 타임아웃이 트리거되지 않는 경우가 많아서, 개발 DB 단계에서 실제 쿼리 응답 시간이 어느 정도 나오는지 보고 넘어갔다.
코드 리뷰 때는 수정한 로직이 기존 흐름에 영향 없는지를 중심으로 봤다. Feature가 비활성화된 시스템에서 기존과 동일하게 동작하는지, 파라미터가 없을 때(null, 빈 값) 폴백이 제대로 동작하는지가 확인 포인트였다.
작은 수정들이지만 이런 게 쌓이면 시스템 전반의 신뢰도가 달라진다. 타임아웃 하나 제대로 잡혀 있는 것, Feature 분기가 의도대로 도는 것, 이런 것들이 겉으로 드러나는 기능은 아니지만 운영 안정성의 기반이 된다.
댓글 0
첫 댓글 달아줘.