자동화 slecs

결제 알림을 텔레그램·디스코드 이중화하고 비즈니스 로직에서 분리

목차

결제 알림이 텔레그램 봇 토큰 만료 한 번에 전부 막히는 구조는 오래 전부터 부채였다. 단일 채널 의존도가 높다는 걸 알면서도 "아직 멀쩡하니까" 미뤘는데, 이번에 디스코드 웹훅을 붙이면서 기회 삼아 알림 레이어 전체를 뜯어고쳤다.

채널을 고를 때 따진 것들

후보는 슬랙·디스코드·이메일이었다. 팀 사이즈나 워크플로에 따라 답이 다르지만, 지금 상황에서 기준은 세 가지였다 - 인증 복잡도, 포맷 표현력, 모바일-데스크톱 커버 범위.

항목 텔레그램 디스코드 슬랙
인증 부담 봇 토큰 + chat_id 웹훅 URL 1개 워크스페이스 토큰
메시지 포맷 마크다운 제한적 Embed 풍부 Block Kit 무거움
운영 친화도 모바일 푸시 강함 데스크톱 알림 강함 채널 정리 편함

디스코드 웹훅은 URL 하나로 끝난다. Embed를 쓰면 색상, 필드, 타임스탬프를 구조화할 수 있어서 충전 성공/실패/지연을 시각적으로 구분하기 좋다. 슬랙 Block Kit도 표현력은 비슷한데 JSON이 너무 장황하고, 이메일은 실시간 알림 용도로는 맞지 않았다. 결국 텔레그램은 모바일 쪽 담당, 디스코드는 데스크톱 쪽 담당으로 역할을 쪼갰다.

구현하면서 진짜로 막혔던 지점

채널 추가 자체는 30분이면 끝난다. 오래 걸린 건 기존 코드의 냄새를 같이 제거하는 과정이었다.

동기 호출 문제. 처음엔 그냥 텔레그램 호출 아래에 디스코드 호출을 줄줄이 붙였다. 테스트하다 보니 외부 API 두 곳을 순서대로 기다리면서 결제 콜백 응답이 늦어지는 게 눈에 보였다. 알림 실패가 결제 트랜잭션 실패로 이어지면 안 되니, 알림 전체를 비동기 큐로 빼고 본 로직과 완전히 분리했다. 알림이 죽어도 결제 흐름엔 영향 없는 구조.

메시지 빌더 분기. 동일 이벤트를 두 채널로 보내다 보니 채널마다 포맷팅이 달라서 if/else가 중간에 끼어들었다. 공통 DTO 하나를 정의하고, 각 채널 어댑터가 그걸 받아서 자기 포맷으로 변환하게 바꿨다. 나중에 카카오워크나 이메일을 추가할 때도 어댑터 하나만 구현하면 되는 구조.

[입금 이벤트] → publish → [알림 라우터]
                          ├─ 텔레그램 어댑터  (MarkdownV2 변환)
                          └─ 디스코드 어댑터  (Embed JSON 변환)

비즈니스 로직 오염. 가장 큰 문제는 따로 있었다. 입금 처리 핸들러 안에 결제대행사 응답 파싱 코드와 알림 호출 코드가 섞여있었다. 파싱 로직을 고치려다가 알림 관련 분기를 같이 건드려야 하는 상황이 반복됐다. 이번에 이벤트 발행 → 리스너 구조로 빼내면서 핸들러는 파싱과 상태 갱신에만 집중하게 됐다. 알림은 이벤트 수신 후 별도 레이어에서 처리.

텔레그램 기존 코드 정리. 이왕 손대는 김에 오래된 냄새들도 같이 제거했다.

  • 코드에 하드코딩돼 있던 봇 토큰 → 환경변수 통일
  • 재시도 로직이 사실상 무한루프 가능성이 있었음 → 지수 백오프 + 최대 3회 캡
  • 메시지 길이가 4096자 넘으면 잘리던 버그 → 청크 분할 후 순차 전송

재시도 캡을 걸 때 한 가지 고민이 있었다. 3회 실패 후 조용히 버리면 운영팀이 놓칠 수 있으니, 실패 자체를 별도 에러 로그 채널에 기록하도록 했다. 알림 실패를 알리는 알림. 좀 우습지만 실제로 유용하다.

분리가 진짜 수확이었음

채널 이중화는 명목상 목표였고, 실제로 얻은 건 알림 레이어의 독립이었다. 비즈니스 로직과 알림이 결합되면 두 가지 문제가 생긴다 - 테스트할 때 외부 API를 모킹해야 하고, 채널을 추가하거나 바꿀 때 로직 코드를 건드려야 한다. 둘 다 나중에 반드시 사고 친다.

이벤트 기반으로 빼내면 반대가 된다. 핸들러 테스트에서 알림은 신경 안 써도 되고, 새 채널은 리스너 하나 추가로 끝난다. 어댑터 패턴과 결합하면 기존 코드 변경 없이 확장이 가능해진다 - 교과서에서 읽던 OCP가 실제로 체감되는 순간이다.

운영팀 쪽 피드백은 단 한 줄이었다. "텔레그램 안 와도 디스코드 보고 알아챘어요." 그걸로 충분했다. 중복 알림이 오히려 피로하다는 의견이 나올 줄 알았는데, 채널별 역할이 나뉘어져 있어서인지 그런 반응은 없었다. 다음에 채널 하나를 더 추가해야 할 때는 어댑터만 작성하면 된다. 구조가 준비됐으니 그때는 진짜로 30분짜리 작업이 될 거다.

댓글 0

첫 댓글 달아줘.