수수료 정책을 수정하면 회원 등급으로 전파되는 기능에 영향 등급 수를 보여 주고 확인받는 절차를 붙이려 했다. 편집 화면의 저장 경로 FeePolicyController.update() 를 찾아 거기에 넣고 배포 직전에 다른 경로가 있는지 훑었다.
Table of contents
Open Table of contents
증상 — 저장 경로가 하나가 아니었다
정책 목록에서 연필 아이콘으로 taker_rate 만 바로 고치는 FeePolicyQuickEditController 가 따로 있었다. 별도 컨트롤러와 별도 서비스 메서드를 타므로 내가 손댄 저장 경로를 거치지 않는다.
그쪽에서도 FeePolicyChangedEvent 전파는 똑같이 일어난다. 확인 절차는 한쪽에만 붙어 있고 다른 쪽으로는 그대로 나가는 상태였다.
원인 — 별도 경로가 생긴 경위
git log 를 보니 목록에서 바로 요율을 고치는 기능이 나중에 추가된 것이었다. 편집 화면을 열지 않고 빠르게 바꾸는 용도였으므로 전체 저장 로직이 필요 없다고 본 것이다.
요율만 바꾸는데 무거운 경로를 재사용할 이유가 없으니 합리적인 판단이었다. 다만 전파는 양쪽 다 하므로 보호가 필요한 지점도 양쪽이 된다.
조치 — 최종 지점에서 역추적
두 가지 방법이 있었다. 서비스 메서드 이름으로 검색해 저장 경로를 찾는 것과, 전파가 결국 jmsTemplate.convertAndSend("fee.policy.changed") 로 ActiveMQ 에 넣는 것이므로 그 호출자를 전부 역추적하는 것이다. 뒤쪽을 골랐다. 이유는 두 경로의 메서드 이름이 달라서 앞쪽으로는 하나만 검색하고 놓쳤을 것이기 때문이다. 대신 호출자 트리가 깊어 반나절이 드는 것을 감수했다.
결과에서 거슬러 올라가면 이름이 무엇이든 그 결과를 내는 자리가 전부 나온다.
주의 — 부분 수정이 남기는 것
이 건에서 가장 중요한 것은 고쳤다고 보고하기 전에 경로를 다 찾았는지 확인하는 일이었다. 한쪽만 고치고 완료로 보고하면 나중에 같은 증상이 다시 나온다.
그때는 아무도 둘째 경로를 의심하지 않는데 이미 고쳤다는 기록이 있기 때문이다. 부분 수정이 미수정보다 나쁠 수 있는 것은 그 기록이 다음 조사를 막기 때문이다.
실측이 지운 걱정
확인 절차를 만들면서 화면에 보여 줄 영향 등급 목록이 없다는 문제도 나왔다. 편집 화면이 쓰는 GET /api/fee-policies/{id} 가 member_grades 를 전혀 로드하지 않아서 추가하려니 부하가 걱정됐다.
등급 개수와 fee_policy_id 인덱스와 EXPLAIN 을 실측하니 무시할 수 있는 수준이었다. 걱정만 하고 안 넣었으면 화면이 계속 정보 없이 동작했을 것이고 실측 없이는 그 판단을 못 했다. 자동 전파 여부 auto_propagate 는 정책 쪽에 있을 줄 알았는데 마켓 설정에 있었고, 컬럼이 아니라 @Transient 접근자로 구현돼 있어서 관계처럼 보이지만 매번 서브쿼리를 타는 형태였다.
정리
- 같은
FeePolicyChangedEvent를 내는 경로가 여럿이면 보호도 여럿이어야 한다 - 나중에 추가된 빠른 경로가 기존 경로를 안 거칠 수 있다
- 메서드 이름으로 검색하면 이름이 다른 경로를 놓친다
convertAndSend최종 지점에서 호출자를 역추적하는 편이 확실하다- 한쪽만 고치고 완료로 보고하면 다음 조사가 막힌다
- 부분 수정이 미수정보다 나쁠 수 있다
- 부하가 걱정되면 개수와 인덱스와
EXPLAIN을 실측한다 - 플래그가 예상 밖에 있으면 값을 읽는 코드를 따라가야 찾는다