요구사항에서 모바일이 60퍼센트 입니다. 끊김은 예외가 아니라 정상 상황입니다. 그래서 업로드는 "성공 또는 실패"가 아니라 재개할 수 있는 상태를 가져야 합니다.
재개하려면 상태가 어딘가 있어야 한다
파일을 파트로 쪼갰다면 어느 파트까지 올라갔는지 알아야 이어서 보낼 수 있습니다. 그 상태를 누가 들고 있느냐로 갈립니다.
| 상태를 두는 곳 | 재개 가능 범위 | 한계 |
|---|---|---|
| 클라이언트 메모리 | 같은 화면에서 일시 중단 | 앱을 닫으면 사라진다 |
| 클라이언트 저장소 | 앱을 다시 켜도 이어감 | 기기를 바꾸면 못 이어간다 |
| 서버의 업로드 세션 | 어느 기기에서도 이어감 | 세션 정리 정책이 필요하다 |
스토리지에 물어보는 방법도 있습니다. 이미 올라간 파트 목록을 조회해 빠진 것만 보내는 방식입니다. 이러면 클라이언트가 상태를 안 들고 있어도 됩니다.
재시도는 중복을 만든다
끊김의 절반은 응답을 못 받은 것입니다. 요청이 서버에 닿았는지 알 수 없습니다.
클라이언트가 파트를 보냈다
응답을 받기 전에 연결이 끊겼다
서버는 받았을 수도 있고 못 받았을 수도 있다
클라이언트는 다시 보낸다
파트 업로드는 같은 번호에 덮어쓰므로 두 번 보내도 결과가 같습니다. 문제는 업로드 완료 처리입니다. 완료 요청이 두 번 들어오면 파일이 두 개 만들어지거나 알림이 두 번 갑니다.
그래서 멱등 키를 씁니다. 클라이언트가 업로드를 시작할 때 키를 하나 만들고 완료 요청에 함께 보냅니다. 서버는 같은 키를 이미 처리했으면 새로 만들지 않고 앞의 결과를 돌려줍니다.
재시도 간격을 두는 이유
끊긴 직후 곧바로 다시 보내면 대개 또 실패합니다. 원인이 아직 그대로이기 때문입니다. 간격을 점점 늘리고 약간의 무작위를 섞습니다.
무작위가 더 중요합니다. 없으면 같은 시점에 끊긴 클라이언트 수천 대가 같은 간격을 세다가 같은 순간에 동시에 재시도해서, 서버가 회복하려는 순간에 다시 밀려 들어옵니다.
무한 재시도는 장애를 늘린다
서버가 이미 힘든 상태에서 모든 클라이언트가 끝없이 재시도하면 회복을 막습니다. 시도 횟수 상한을 두고, 넘으면 사용자에게 알리고 멈춥니다. 자동 재시도가 항상 친절한 것은 아닙니다.