결제대행사 은행별 핸들러를 추상 계층으로 통합해 오류 분류 일원화
목차
배경
결제대행사 연동에서 은행별 핸들러가 6개쯤 있었음. 각자 try-catch 도배되어 있고 에러 코드 매핑도 핸들러마다 따로 적혀 있어서, 같은 "타임아웃" 케이스를 어떤 핸들러는 재시도, 어떤 핸들러는 즉시 실패로 처리하고 있었음. 운영에서 이슈 올라올 때마다 "이 은행은 또 왜 다르냐"가 반복됨. 더는 못 참겠어서 추상 계층을 다시 깎았음.
추상 계층에 뭘 올릴지
원래 추상 클래스에 메서드 하나만 있었는데, 공통화 가능한 걸 추려보니 의외로 많았음.
- 요청/응답 로깅 포맷
- 타임아웃·연결 끊김·잔액 부족 같은 표준 예외 분류
- 재시도 가능 여부 판단
- 결과 코드 → 내부 도메인 코드 매핑 골격
은행별로 다른 건 진짜 "은행별로 다른 것"만 남기는 게 목표였음. 추상 메서드 시그니처는 이렇게 정리.
parseResponse(raw) // 은행별 구현
classifyError(parsed) // 추상에서 기본 제공, 필요시 override
isRetryable(category) // 추상에서만 정의
AI 보조 로직 어디에 끼웠나
처음엔 모든 에러를 LLM에 던져서 분류시키려 했는데, 비용·지연·재현성 셋 다 안 맞았음. 결국 결정 트리 우선, AI는 fallback 으로 정착.
| 단계 | 처리 방식 | 비고 |
|---|---|---|
| 1 | 코드/메시지 정규식 매칭 | 90%는 여기서 끝 |
| 2 | 룰 기반 카테고리 분류 | 재시도 여부 결정 |
| 3 | AI 분류 호출 | unknown 만 |
| 4 | AI 결과를 룰로 흡수 | 다음엔 1단계에서 잡힘 |
특히 4번이 핵심이었음. AI가 분류한 결과를 그냥 쓰면 매번 호출해야 하니까, 분류 결과를 정규식 룰로 환원해서 저장. 하루 지나니 AI 호출이 거의 안 일어났음.
삽질 포인트
- 추상 메서드 default 구현을 너무 친절하게 짰더니 특정 은행 핸들러가 override 안 한 채로 운영 나감. 결국 default 를 throw UnsupportedOperationException 으로 바꿔서 강제로 결정하게 만듦.
- AI 응답에 카테고리 외 텍스트가 섞여 들어와서 enum 변환이 깨짐. JSON 강제 + 화이트리스트 검증 두 번 둠.
- 재시도 가능 판단을 추상 계층에 두면서 멱등성 키 정책도 같이 손봐야 한다는 걸 뒤늦게 깨달음. 이건 별도 티켓으로 분리.
남은 것
핸들러별 코드 라인 수는 평균 40% 줄었고, "이 은행만 왜" 류 이슈는 일주일째 안 올라옴. 다만 AI fallback 의 비용 모니터링 대시보드는 아직 임시 그래프 수준이라, 룰 흡수율이 떨어지는 순간 못 잡을 수 있음. 이건 다음 스프린트.
끝
댓글 0
첫 댓글 달아줘.