느린 회선에서 15번 다시 받아도 끝나지 않던 에이전트 업데이트 — HTTP Range로 이어받기 구현

초당 5~6KB 회선에서 14.7MB 설치본을 1.5시간 동안 15번 시도해도 매번 0바이트부터 다시 받다 끊겼다. 끊긴 지점을 true로 돌려주던 다운로드 함수가 원인이었다. WinINet의 Range·If-Range 요청으로 이어받기를 구현한 과정을 정리한다.

현상

느린 회선(초당 5~6KB)을 쓰는 한 노드가 14.7MB 설치본을 1.5시간 동안 15번 시도했는데, 매번 0바이트부터 다시 받고 최대 3.6MB에서 끊겼다. 15번 중 6번은 nginx의 send_timeout(60초)에 걸렸고, 9번은 노드·회선 쪽에서 연결이 닫혔다.

원인은 다운로드 함수(RequestFile)가 전송 중간에 끊겨도 true를 돌려준다는 데 있었다. 잘린 파일은 해시 검증에서 떨어졌고, 남는 기록은 「AGENT UPDATE FAILED」뿐이라 왜 실패했는지 알 수 없었다.

원칙

  • 이어받기로 근본 해결한다.
  • 시간 제한을 두지 않는다. 진척이 있는 동안은 계속 시도한다.
  • 실패 이유는 agent.error.log에 한 줄 남긴다.

설계

YAgent::DownloadFileResume(common/Http.cpp, WinINet 기반)으로 구현했다.

  • 다운로드 중인 파일은 <경로>.part와 <경로>.part.info(URL·ETag 저장) 두 개로 관리한다.
  • 이어받을 때는 Range 헤더와 If-Range(강한 ETag)를 함께 보낸다.
  • 서버 응답이 206이면 Content-Range를 엄격히 맞춰서 기존 .part에 이어 붙인다.
  • 200이 오면(서버가 Range를 무시했다는 뜻) .part를 비우고 새 ETag를 적은 뒤 처음부터 받는다.
  • 416(bytes */전체)이고 그 전체 크기가 이미 받아 둔 크기와 같으면 그걸로 마무리한다.
  • 받은 크기가 전체 크기와 같을 때만 최종 경로로 옮기고, 기존 해시·서명 검증을 그대로 거친다. 검증에 실패하면 파일을 삭제해 다음 시도는 처음부터 받게 한다.

남은 일

  • 빌드 뒤 느린 회선 가상 머신에서 QA 시험을 한다.
  • 서버 쪽 send_timeout 조정은 별도로 완료했다.

Orange Platform 에이전트 업데이트 다운로드 안정화 작업 정리입니다.