개발
블로그 불러오는 중...
문의 보내기
남겨주면 블로그 주인에게 바로 전달돼요.
개발
회사에서 메일함을 가져오는 코드가 간헐적으로 멈추는 문제가 발생 했다. 처음에는 로그 상 특별한 에러가 없었기 때문에 단순한 이메일 서버 문제라고 판단 하고 재시작 처리만 했지만, 이후에도 일부 케이스에서 메일이 제대로 읽히지 않는 현상이 계속 되었다.
같은 증상이 반복 됐고, 특정 이메일 에서 재현 된다는 점이 점점 분명 해졌다. 그래서 라이브러리를 쓰는 입장에서 라이브러리를 의심 하는 단계로 들어 갔다.
문제를 해결 하기 위해 직접 소스 코드를 분석 했고, 의심 가는 이메일들을 따로 저장 하면서 원인을 추적 해 나갔다. 처음에는 인코딩 문제나 네트워크 타임아웃을 의심 했지만, 같은 메일을 여러 번 받아도 같은 자리에서 끊긴다는 패턴이 보이기 시작 했다.
그 과정에서 POP3 프로토콜의 RFC 문서를 읽게 되었고, 문서에 정의된 일부 규칙이 코드에 반영되어 있지 않다는 것을 발견 했다.
RFC 1939 - Post Office Protocol Version 3 의 section 3 에는 다음과 같이 명시 되어 있다.
Responses to certain commands are multi-line. In these cases, which are clearly indicated below, after sending the first line of the response and a CRLF, any additional lines are sent, each terminated by a CRLF pair. When all lines of the response have been sent, a final line is sent, consisting of a termination octet (decimal code 046, ".") and a CRLF pair.
즉 멀티라인 응답의 진짜 종료자는 CRLF + . + CRLF 다. 바이트 시퀀스로 적으면 \r\n.\r\n 이 되어야 한다.
그런데 기존 코드는 단순히 응답이 .\r\n 으로 끝나는지를 보고 있었다.
// before — 응답이 .\r\n 로 끝나면 종료로 간주
if (data.endsWith('.\r\n')) {
onResponseComplete();
}문제는 본문 라인 자체가 마침표 + 줄바꿈으로 끝나는 경우 였다. 예를 들어 메일 본문 한 문장이 Thanks. 로 끝나면 그 줄도 .\r\n 패턴에 걸린다. 그래서 응답이 다 읽히지도 않았는데 종료 시그널로 오인 해서 끊어 버리고, 그 결과 일부 메일에서만 간헐적 누락이 발생 했다.
수정은 RFC 가 말하는 대로 종료자를 정확히 잡아 주는 것이었다.
// after — RFC 1939: 진짜 종료자는 CRLF + . + CRLF
if (data.endsWith('\r\n.\r\n')) {
onResponseComplete();
}이 한 줄을 바꾸자, 그동안 문제가 되었던 이메일들도 정상적으로 읽히기 시작 했다.
문제가 되는 오픈소스 라이브러리 (yapople) 에 수정을 반영 하기 위해 PR 을 보냈다 → https://github.com/agsh/yapople/pull/32
PR 에서는 문제 상황과 함께 RFC 문서의 해당 문장을 인용 하며, 수정이 필요한 이유를 상세히 설명 했다. 단순히 "버그를 고쳤다" 가 아니라 "RFC 의 어느 문장과 어긋났다" 를 근거로 들어야, 메인테이너 입장에서 머지를 결정 하기 쉽다는 것을 그제야 알았다.
PR 을 보낸 뒤, 라이브러리의 원 작성자인 @agsh 님께서 리뷰를 남겨 주셨고, 그에 따라 코드를 조금 더 수정 해서 반영 했다.
오픈소스라는 특성상, 내 코드가 다른 서비스들에 영향을 줄 수도 있다는 걱정에 처음엔 소극적으로 수정 했었다. 종료자 검사 로직만 살짝 우회 하는 보수적인 변경 이었다. 그런데 오히려 @agsh 님이 내가 처음에 시도 했던 방식 — 종료자 패턴 자체를 RFC 기준으로 교체 하는 쪽 — 이 더 좋다며 추천 해 주셨고, 그제서야 확신을 가지고 본래 의도 대로 수정을 다시 올릴 수 있었다.

@agsh 님이 남겨 주신 리뷰 코멘트
결과적으로 해당 PR 이 머지 되었고, 라이브러리도 새 버전으로 업데이트 되었다. 그리고 contributor 목록에 내 이름을 올릴 수 있었다.
이후 블로그를 만들면서 Strapi 에도 작게나마 기여한 적이 있다. 복잡한 수정은 아니었지만, 오픈소스 코드 구조를 읽고 직접 개선 포인트를 찾으며 참여 하는 경험 자체가 의미 있었다.
오픈소스에 처음 기여 한다는 건 쉽지 않은 일이었다. 하지만 한 줄 한 줄 남의 코드를 읽고 이해 해 가며 내 코드도 함께 성장 할 수 있었다고 느꼈다.
이번 경험에서 가장 크게 남은 건 두 가지였다.
첫째, "라이브러리를 의심 해도 된다" 는 감각. 그동안은 내가 쓰는 라이브러리에서 문제가 나면 으레 내 사용법을 먼저 의심 했었다. 이번 일을 계기로, 증상이 라이브러리 내부 로직으로 좁혀 들어 가면 더 이상 망설이지 않고 소스를 까 보게 되었다.
둘째, "근거가 곧 머지" 라는 감각. 코드 변경 자체보다, RFC 라는 명확한 근거를 들고 가는 것이 PR 의 절반이었다. 사내 PR 에서도 이후로는 변경의 근거 문서 를 같이 거는 습관이 생겼다.
앞으로도 비슷한 흐름 — 사내에서 부딪힌 문제를 추적 하다 OSS 까지 흘러가는 — 이 또 생기면 주저 없이 PR 을 보내 보려고 한다.