통합과 배포 · HTTP API 통합 · 이론
연결 거부와 타임아웃은 완전히 다른 소식이다
한 줄 요약
"API 가 안 된다" 는 신고에서 가장 많은 정보를 담고 있는 것은 로그가 아니라 실패 메시지의 정확한 문구다.
왜 이게 필요했나
고객이 "API 가 죽었어요" 라고 말할 때, 그 문장 뒤에는 완전히 다른 다섯 가지 상황이 숨어 있을 수 있습니다. 그리고 어느 것인지는 실패 메시지 한 줄로 대부분 갈립니다.
Connection refused — 나쁜 소식이 아닙니다. 패킷이 목적지까지 갔다가 돌아왔다는 증거입니다. 라우팅, 방화벽, NAT 같은 경로상의 모든 관문을 이미 통과한 것이고, 남은 원인은 대상 호스트 한 대 안으로 좁혀집니다. 프로세스가 죽었거나, 다른 포트에서 듣고 있거나, 0.0.0.0 이 아니라 127.0.0.1 에만 바인딩돼 있습니다.
Connection timed out — 아무 정보가 없습니다. 아무도 대답하지 않았다는 뜻이고, 방화벽이 조용히 버렸을 수도 라우팅이 없을 수도 상대가 과부하일 수도 있습니다. 실무에서 쓰는 방화벽은 거의 언제나 조용히 버리는 정책이라, 방화벽이 막으면 refused 가 아니라 timeout 이 납니다. 그래서 refused 를 보고 방화벽을 뒤지는 것은 이미 통과한 관문을 다시 확인하는 일입니다.
Name or service not known — 대상 서버로 패킷이 한 개도 안 나갔습니다. 방화벽 로그에 아무것도 없는 것이 정상이고, 조사는 이름 해석 쪽으로 갑니다.
여기에 실패까지 걸린 시간을 함께 재면 확신이 생깁니다. 몇 밀리초 만에 끝났으면 왕복이 완료된 것(refused)이고, 2분 7초쯤에서 끊겼으면 커널이 SYN 재전송을 전부 소진한 것입니다. 앱 타임아웃을 30초로 설정했는데 실제로는 127초에 실패했다면, 그 설정이 적용되지 않고 있다는 신호입니다.
어떻게 동작하나
연결이 되고 나면 다음은 상태 코드입니다. 여기서 가장 자주 오진되는 것이 502 와 504 입니다.
502 는 응답을 못 받은 것이 아니라 유효하지 않은 응답을 받은 것입니다. 응답이 오긴 왔는데 프록시가 파싱하지 못한 경우도 502 입니다. 그래서 502 에 타임아웃을 늘리는 것은 아무 효과가 없습니다. 시간 안에 응답을 못 받은 경우는 504 입니다.
그리고 문서가 부실한 API 에 붙을 때 반드시 확인해야 할 것이 세 가지 더 있습니다.
페이지네이션의 끝을 어떻게 아는가. has_next 같은 명시적 플래그가 있으면 그것을 믿고, 없으면 빈 배열이 올 때까지 돕니다. 여기서 흔한 버그는 첫 페이지의 total 만 보고 페이지 수를 계산한 뒤 실제로는 마지막 페이지를 빠뜨리는 것입니다. 나눗셈의 나머지를 잊는 고전적 실수입니다.
일시적 실패를 어떻게 다루는가. 503 이나 네트워크 오류는 재시도로 넘어가는 경우가 많습니다. 다만 재시도해도 되는 것과 안 되는 것이 갈립니다. 조회는 몇 번을 반복해도 같지만, 생성 요청을 재시도하면 중복이 만들어집니다. 4xx 는 요청을 고치지 않으면 몇 번을 보내도 같은 결과이므로 재시도 대상이 아닙니다.
문서에 없는 결측이 얼마나 있는가. 이것이 실무에서 가장 자주 사람을 잡습니다. 명세에는 필수라고 적힌 필드가 실제 응답에서는 빈 문자열로 오는 경우가 흔하고, 그 값을 그대로 집계에 넣으면 조용히 틀린 숫자가 나옵니다.
현장에서 만나는 모습
그래서 새 API 에 붙을 때의 첫 작업은 코드를 쓰는 것이 아니라 전수 조사입니다. 모든 페이지를 한 번 돌면서 총 건수, 합계, 그리고 각 필드의 결측 건수를 세어 봅니다.
이 한 번의 조사가 이후 몇 주의 디버깅을 없앱니다. "총 60건 중 6건은 region 이 비어 있습니다. 이 건들을 어떻게 처리할까요" 라는 질문을 첫 주에 던지면, 나중에 지역별 매출 합계가 안 맞는다는 신고가 오지 않습니다.
다음 실습에서 할 것
문서가 한 페이지짜리 위키가 전부인 주문 API 에 붙어, 버전을 확인하고, 모든 페이지를 돌며 총 건수와 합계를 내고, 문서에 없는 결측을 세고, 불안정한 엔드포인트를 재시도로 통과합니다.