Troubleshooting 배포 중 업로드 중단 - 100-hours-a-week/KTB4-2nd-Cloud GitHub Wiki
2026-09-29
Backend 로그 수집 설정을 반영하려고 Production 배포를 실행했는데, 그때 팀원이 여행 109에 사진을 올리고 있었습니다. 14시 4분에 Discord로 Alarm이 왔습니다.
ALARM | yeodam-v1-nginx-5xx
Threshold Crossed: 18 >= 5
Nginx 로그를 보니 마지막 사진 Batch 요청이 약 50MB를 보낸 뒤 143초 만에 502로 끝났습니다.
POST /api/trips/109/initial-attachments
status=502 request_length=50915370 request_time=143.370
바로 뒤에 Frontend와 Backend 요청도 잠깐 500, 502를 반환했습니다.
Nginx Error 로그에는 Backend 연결이 먼저 끊기고, 이어서 FE, BE 포트 모두 연결이 거부된 기록이 있었습니다.
upstream prematurely closed connection while reading response header from upstream
connect() failed (111: Connection refused) while connecting to upstream
같은 시각에 배포가 FE, BE 컨테이너를 교체하고 있었습니다. 새 Backend는 14시 4분 12초부터 기동 로그를 남겼고, 로그의 release도 배포한 이미지 커밋과 같았습니다.
배포한 변경 내용이 문제가 아니라, 처리 중인 요청이 있는 상태에서 컨테이너를 교체한 게 원인이었습니다.
문제의 요청 전까지 10개 Batch는 모두 204로 끝났습니다. 끊긴 마지막 Batch를 배포 뒤 다시 보내자 409가 돌아왔습니다. 서버에는 일부 반영됐는데 응답만 끊겼을 가능성이 있어서, 여행 109의 저장 상태는 별도로 확인할 항목으로 남겼습니다.
배포가 끝난 뒤 외부에서 Backend health가 UP인 것과, 새 로그가 CloudWatch에 들어오는 것을 확인했습니다. 서비스는 바로 돌아왔습니다.
같은 일을 막으려면 배포가 이 순서로 진행돼야 합니다.
flowchart LR
A["신규 업로드 차단"] --> B["진행 중인 업로드<br/>끝날 때까지 대기"]
A --> C["Worker 현재 작업<br/>끝날 때까지 대기"]
B --> D["App, Worker 교체"]
C --> D
D --> E["검증 후<br/>업로드 재개"]
CD 설계에 이미 이 Drain 순서가 있었지만, Backend에 활성 업로드 수를 알려주는 방법이 아직 없어 배포에 연결하지 못한 상태였습니다. Backend 팀과 조회 방식을 정한 뒤 배포 절차에 넣기로 했고, 그전까지는 진행 중인 업로드가 없는 시간을 확인하고 배포합니다.
배포 워크플로가 성공하는 것만 확인했고, 배포 중에 사용자 요청이 안전한지는 검증하지 않았습니다. 설계에서 나중으로 미뤄둔 Drain이 운영에 꼭 필요한 조건이라는 걸 실제 요청이 끊기고 나서 확인했습니다.
그래도 Nginx 5xx Alarm이 바로 울려서 영향 범위를 빠르게 좁힐 수 있었습니다.