개발 slecs

알림 채널 다중 전송을 병렬 디스패치로 개선

목차

단일 채팅방으로만 날리던 알림 구조를 복수 대상으로 확장하면서, 직렬 전송이 만들어내던 지연 문제를 같이 해결한 작업이다.


왜 여러 채팅방이 필요했나

처음 알림 시스템을 만들 때는 단순했다. 메시지 한 건 → 채팅방 하나. notify.py 안에서 단일 chat_id를 받아 API 호출을 하나 날리면 그게 끝이었다. 그런데 시스템이 붙는 팀이 늘어나고, 채널 구분 요청이 쌓이기 시작했다. "우리 팀 채널에도 같이 보내줄 수 있어요?", "운영자 채널이랑 개발 채널 둘 다 받아야 해요" — 이런 요청이 하나둘이 아니었다.

그때마다 코드 레벨에서 임시로 chat_id를 추가로 넣어주는 형태로 처리했는데, 사실 이건 팀 입장에서 최악의 선택이었다. 기능 확장이 아니라 코드 중복이 쌓이는 방식이었고, 나중에 대상 채널이 바뀔 때마다 코드를 직접 건드려야 했다. 언젠간 반드시 정리해야 할 기술 부채였다.


병렬 디스패치를 선택한 이유

복수 대상 지원 자체는 어렵지 않다. 리스트를 받아서 루프 돌리면 된다. 문제는 직렬 루프의 지연이었다.

예를 들어 채팅방이 3개인데, 각 API 호출이 200ms씩 걸린다면 직렬로 처리하면 최소 600ms다. 알림 특성상 "빠르게 도착해야 의미 있는" 케이스가 많다. 장애 알림이나 결제 이상 감지 같은 상황에서 0.6초 지연은 체감된다. 그리고 앞 채널 API가 timeout 나거나 느려지면 뒤 채널까지 줄줄이 늦어지는 구조는 팀원한테 설명하기도 민망했다.

# Before: 직렬 전송
def notify(message: str, chat_id: str):
    _send(chat_id, message)

# After: 복수 대상 + 병렬 디스패치
import asyncio

async def notify(message: str, chat_ids: list[str]):
    await asyncio.gather(*[_send(chat_id, message) for chat_id in chat_ids])

asyncio.gather를 쓰면 각 _send 코루틴이 동시에 실행된다. 채널이 몇 개든 전체 소요 시간은 "가장 느린 채널 하나"의 응답 시간에 수렴한다. 직렬 대비 채널 수가 늘수록 이득이 커지는 구조다.

방식 채널 3개 기준 소요 시간 한 채널 지연 시 영향
직렬 루프 각 응답 시간 합산 이후 채널 전체 지연
asyncio.gather 가장 느린 응답 시간 해당 채널만 지연

notify.py 한 파일에서 다 바꾼 것의 의미

변경 파일이 notify.py 단 하나다. 얼핏 작아 보이지만, 이 파일이 알림 발송 로직의 진입점이라는 점에서 파급 범위는 넓다. 이 파일을 호출하는 모든 곳에서 chat_id를 단일 문자열로 넘기던 인터페이스가 리스트로 바뀌는 거라, 호출부 수정이 같이 따라왔을 거다.

이럴 때 팀 리드로서 신경 쓰는 부분이 하나 있다. 인터페이스 변경을 어떻게 롤아웃하느냐. 기존 단일 chat_id 호출을 한 번에 다 바꾸는 대신, 내부에서 str | list[str]을 모두 받도록 처리하거나, 하위 호환을 잠시 유지하고 마이그레이션 기간을 두는 방식도 고려해볼 수 있다. 코드리뷰 때 이런 부분을 짚어주는 게 시니어 역할이다 — "동작은 맞는데, 기존 호출부가 한 번에 다 같이 업데이트됐는지 확인했어?"


회고

솔직히 이 작업을 좀 더 일찍 해줬어야 했다. 요청이 쌓이는데 임시 패치로 버틴 기간이 길었다. 알림 시스템은 "잘 돼도 아무도 모르고, 늦거나 안 가면 바로 문제 제기되는" 구조라, 적당히 돌아가면 우선순위가 계속 밀린다. 팀에서도 이런 인프라성 작업의 우선순위를 올리는 게 항상 쉽지 않다는 걸 다시 느꼈다.

병렬 디스패치로 바꾸고 나서 팀원 중 한 명이 "속도 차이가 체감될 줄은 몰랐다"고 했는데, 그 한 마디가 이 작업 전체를 정리해주는 것 같았다. 기술적으로 복잡한 작업은 아니었지만, 제때 하지 않으면 조용히 비용이 쌓이는 종류의 일이다.

다음


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.