사이드프로젝트 slecs

결제 입금 알림이 엉뚱한 채팅방으로 가던 오배송 문제 수정

목차

채팅방 매칭이 어긋나던 문제

파트너가 결제대행사로부터 입금 알림을 받아 메신저 채팅방으로 푸시하는 흐름이 있었음. 그런데 같은 파트너가 여러 거래 은행을 동시에 쓰는 케이스가 늘면서, 알림이 엉뚱한 방으로 들어가는 사고가 잦아짐.

원인은 단순했음. 채팅방을 찾을 때 쓰던 키가 너무 헐거웠음.

  • 파트너 식별자 하나만 매칭 키로 사용
  • 같은 파트너가 A은행/B은행 채팅방을 둘 다 운영하면 먼저 잡힌 방으로 발사
  • 운영자가 수동 분기를 만들어 두지 않으면 알림이 섞임

시스템 초기에는 파트너당 거래 은행이 하나라는 암묵적 가정이 깔려 있었던 거다. 설계 당시엔 실제로 그랬을 테니 단순 키로 충분했을 것이고, 누군가 일부러 느슨하게 만든 게 아니라 그냥 당시 도메인을 반영한 결과였을 거임. 문제는 현실이 조용히 바뀌었는데 코드가 따라가지 못한 것.

이런 류의 버그가 골치 아픈 건, 틀린 결과를 내면서도 "알림이 가긴 했다"는 시그널 때문에 오랫동안 안 보인다는 점임. 운영자 입장에선 푸시가 도착하면 일단 확인하게 되니까 채팅방이 섞인 걸 한참 뒤에야 눈치채는 경우가 생김. 조용한 오배송.

복합 키로 바꾸기, 그리고 폴백 처리

해법은 키 차원을 늘리는 것이었음. 알림 페이로드에 들어 있는 요청 은행 코드까지 매칭 조건에 포함시켜서 "파트너 + 은행" 조합으로만 채팅방을 찾도록 바꿈.

# 변경 전
room = findRoom(partnerId)

# 변경 후
room = findRoom(partnerId, bankCode)
   ?: fallbackRoom(partnerId)   # 은행 미지정 알림은 기본 방으로

폴백을 살려둔 이유는 과거 데이터 호환임. 은행 코드 없이 등록한 채팅방이 일부 남아 있어서, 새 키로 못 찾으면 예전 방식으로 한 번 더 조회하게 함. 이행 기간이 끝나면 제거할 예정임.

폴백 레이어를 두는 게 항상 좋은 선택은 아님. 실패를 너무 감싸주면 누락을 눈치채기 어려워진다. 그래서 이번엔 폴백 진입 시에도 로그를 남겼음. 폴백을 타고 있다는 사실 자체가 "이 파트너는 아직 마이그레이션 안 됐다"는 신호이기 때문에, 조용히 넘기면 안 되는 경우였음.

복합 키 설계를 할 때 조합 선택 기준도 한 번 정리해두면 나중에 유용함.

키 후보 고려 사항
단일 식별자 도메인 단순할 때만 안전, 확장 시 충돌 위험
식별자 + 속성 속성 값이 알림 페이로드에 안정적으로 있어야 함
식별자 + 속성 + 타입 과잉일 수 있음, 키가 길어질수록 등록 실수 늘어남

이번엔 파트너 + 은행 두 차원으로 충분했음. 세 번째 차원을 넣을 만한 요건이 아직 없었기 때문에 거기서 멈춤. 키를 미리 확장해두는 것도 오버엔지니어링이 될 수 있어서, 요건이 생길 때 늘리는 쪽이 낫다고 봄.

수정 후 매칭 정확도

케이스 이전 이후
단일 은행 파트너 정상 정상
다중 은행 파트너 첫 방으로 몰림 은행별 분리
은행 미상 알림 무조건 매칭 기본 방으로 폴백
미등록 은행 알림 잘못된 방 매칭 실패 로그

매칭 실패를 명시적으로 떨어뜨린 것도 의도였음. 이전에는 잘못 들어가도 운영자가 알림 자체는 받으니까 문제를 못 봤는데, 이제 안 맞으면 안 들어감. 대신 실패 로그를 남겨서 신규 은행 등록 누락을 빠르게 잡을 수 있게 함.

WARN [chat-match] no room matched
   partnerId=*** bankCode=088
   hint=파트너 채팅방에 신규 은행 등록 필요

운영팀이 이 로그만 보고도 어떤 채팅방이 비어 있는지 한 눈에 잡을 수 있게 메시지 포맷도 같이 정리함. "hint" 필드 하나 붙이는 게 사소해 보여도 실제 운영에서 꽤 차이남. 로그 보고 코드 뒤지는 왕복이 없어지니까.

"실패를 잡아서 처리"하는 것과 "실패를 명시적으로 노출"하는 것 사이의 선택이 이런 루팅 시스템에서 늘 나옴. 비즈니스 흐름이 멈추는 게 겁날수록 전자를 택하게 되는데, 그게 쌓이면 나중에 아무도 모르는 조용한 오류가 시스템에 가득 차게 됨. 이번 케이스에선 "안 들어가고 시끄럽게 우는 쪽"이 압도적으로 안전했음.

회고

작업하면서 다시 새긴 것 두 가지.

검색 키는 도메인이 커지는 방향으로 같이 커져야 한다. "지금 충분"한 키는 곧 부족해짐. 이걸 처음부터 완벽하게 예측할 수는 없지만, 도메인 확장 방향에 대한 감각은 키에 반영해두는 게 좋다. 파트너가 멀티테넌트 구조로 가고 있다면 파트너 하위 속성이 키 재료로 쓰일 가능성이 높다는 걸 어느 정도는 예측할 수 있었음.

잘못된 매칭은 미매칭보다 훨씬 위험하다. 이건 이번에 다시 확인했음. 루팅 시스템에서 "일단 어디든 보내는" 정책은 겉으로 안정적으로 보이지만, 내부에서 데이터가 조용히 오염되고 있는 거임. 발각이 늦어질수록 수습 비용이 커짐. 차라리 못 찾고 시끄럽게 우는 쪽이 운영상 안전하다.

다음으로는 채팅방 매핑 자체를 운영자 화면에서 점검·수정할 수 있는 작은 도구를 붙일 차례임. 매칭 정책이 늘어날수록 코드보다 데이터로 푸는 비중이 커질 것 같고, 그 데이터를 관리하는 인터페이스가 없으면 결국 코드 수정 요청이 계속 올 거임. 루팅 로직이 안정되면 그쪽을 봐야겠다.

댓글 0

첫 댓글 달아줘.