블로그

재배포가 실패해도 작동 중인 백엔드는 삭제되지 않습니다

9월 25일, 실패한 재배포 하나가 약 두 시간 반 동안 정상 작동하던 앱의 백엔드를 삭제했습니다. 실패한 배포를 되돌리는 코드가 배포에서 건드린 서버 앱을 모두 삭제했고, 여기에는 배포가 시작되기 전부터 이미 서비스 중이던 앱도 포함되어 있었습니다. 이제는 배포가 새로 만든 앱만 삭제되며, 이미 존재하던 앱은 배포 전에 실행하던 정확한 버전으로 되돌아갑니다. 같은 날 이어진 두 가지 수정으로, 호스팅 플랫폼 자체의 배포 도구가 실패했을 때도 이 되돌리기가 실행되도록 했고, 잠들어 있던 정상 앱이 그 이유만으로 실패 처리되지 않도록 했습니다.

백엔드는 이렇게 배포됩니다

Mythex 앱에 백엔드가 있으면(정적 파일만이 아니라 API나 서버가 있으면), 배포할 때 Dockerfile(앱을 이미지로 패키징하는 레시피)로 백엔드를 빌드한 뒤 그 이미지를 호스팅 플랫폼의 머신들에 올립니다. 그다음 헬스 체크가 새 버전이 실제로 올라와서 계속 실행되는지 확인한 뒤에야 배포를 라이브 상태로 표시합니다.

그 과정에서 무언가 실패하면 롤백이 실행되어 변경을 되돌립니다. 이 롤백을 제대로 만드는 일은 배포에서 거의 무엇보다 중요합니다. 롤백은 이미 무언가 잘못되고 있는 순간에 실행되기 때문입니다.

문제 1: 롤백이 복구해야 할 것을 삭제했습니다

롤백은 배포가 올라간 서버 앱 목록을 가지고 있다가, 실패하면 그 목록의 앱을 모두 삭제했습니다. 처음 배포하는 경우에는 이게 맞습니다. 앱이 방금 만들어졌고 아무것도 그 앱에 의존하지 않으니, 삭제하면 원래 상태로 돌아가기 때문입니다.

재배포에서는 정반대로 잘못된 방식입니다. 앱은 이미 존재했고 실제 방문자에게 서비스하고 있었습니다. 9월 25일에는 약 두 시간 반 동안 살아 있던 앱의 API가 실패한 재배포로 삭제되었습니다.

같은 코드에는 또 다른 실패 방식도 숨어 있었습니다. 삭제가 완료되지 않은 경우, 고장 난 새 이미지가 머신에 그대로 남았는데도 우리는 소유자에게 현재 사이트가 여전히 서비스 중이라고 알리고 있었습니다. 헬스 체크가 실패를 감지할 즈음에는 새 이미지가 이미 모든 머신에 올라가 있습니다. 아무것도 하지 않는 것은 되돌리는 것과 같지 않습니다.

해결책: 만든 것만 삭제하고, 나머지는 복구합니다

이제 배포는 건드리는 서버 앱마다 다음 두 가지를 기록합니다.

  • 이번 배포가 앱을 새로 만들었는지 여부
  • 새로 만든 것이 아니라면, 배포 직전에 어떤 이미지를 실행하고 있었는지

실패하면 각 앱은 다음 세 가지 중 하나로 처리됩니다.

  1. 이번 배포가 만든 앱: 예전과 같이 삭제합니다.
  2. 이미 있었고 이전 이미지를 알고 있음: 같은 설정으로 이전 이미지를 다시 배포합니다. 빌드는 하지 않고 이미지만 되돌립니다.
  3. 이미 있었고 이전 이미지를 모름: 건드리지 않습니다. 복구할 수 없더라도 기존 앱은 절대 삭제하지 않습니다.

이 규칙은 작은 순수 함수로 구현되어 있고 자체 테스트가 있으므로, 결정이 "전부 삭제"로 되돌아가면 테스트가 실패합니다.

문제 2: 배포 도구가 되돌리는 방법을 기록하기 전에 실패할 수 있었습니다

이 수정 직후 빈틈 하나를 더 발견했습니다. 호스팅 플랫폼의 배포 도구는 자체 스모크 체크를 실행합니다. 새 머신이 크래시하면 도구가 오류와 함께 종료됩니다. 하지만 그 시점은 새 이미지가 이미 머신에 올라간 뒤입니다.

우리 코드는 도구가 성공적으로 반환한 뒤에야 앱을 롤백 목록에 등록했습니다. 도구 자체가 배포를 실패시키면 앱은 아직 롤백 목록에 없었고, 아무것도 복구되지 않았습니다. 스테이징 환경에서는 고장 난 재배포 후에도 고장 난 이미지가 계속 서비스되고 있었습니다.

해결책: 시작하기 전에 되돌리는 방법을 등록합니다

이제 앱은 준비되자마자, 그리고 어떤 이미지도 올라가기 전에, 생성 여부와 실행 중이던 이미지와 함께 롤백 대상으로 등록됩니다. 그 뒤에 무엇이 실패하든 롤백은 무엇을 되돌려야 하는지 알고 있습니다. 로컬에서 검증했습니다. 고장 난 재배포가 배포 도구의 스모크 체크에서 실패했고, 이전 버전은 계속 응답했습니다.

문제 3: 잠든 앱이 "시작되지 않음"으로 실패 처리되었습니다

Mythex에서 게시된 앱은 크레딧을 아끼려고 유휴 상태일 때 잠듭니다. 재배포하면 잠든 머신은 멈춘 상태로 남기 때문에, 헬스 체크가 머신을 깨워야 합니다. 그런데 기존 코드는 플랫폼에 머신 시작을 한 번만 요청하고 응답은 무시했습니다.

9월 25일에는 그 시작 요청 하나가 아무 효과 없이 끝났습니다. 정상 작동하던 API가 5분짜리 헬스 체크 내내 멈춘 상태로 있었고, "머신 1대가 시작되지 않음(마지막 상태: stopped)"이라는 이유로 실패 처리되었습니다.

플랫폼이 시작을 거부하는 경우도 실제로 있습니다. 이 문제를 재현하는 동안에도, 우리가 유도하지 않았는데 플랫폼이 "lease currently held"(리스가 이미 점유 중) 충돌을 반환했고, 머신이 업데이트 중일 때는 시작을 거부합니다.

해결책: 계속 요청하고, 문을 두드립니다

이제 헬스 체크는 다음과 같이 동작합니다.

  • 기다리는 동안 멈춘 머신을 시작해 달라고 20초마다 다시 요청합니다.
  • 플랫폼이 거부할 때 무엇이라고 답했는지 기록합니다.
  • 방문자가 보내는 것과 같은 일반 요청을 앱에 한 번 보냅니다. 요청이 도착하면 플랫폼의 프록시가 잠든 머신을 깨웁니다.

실제 플랫폼에서 첫 시작이 거부되도록 만든 임시 앱으로 재현했습니다. 수정 전에는 배포가 91초 후 실패했고, 수정 후에는 20초 만에 배포가 완료되었습니다. 부팅 중 실제로 크래시하는 앱은 여전히 올바르게 실패합니다.

얻은 교훈

  • 롤백은 새로 만든 것과 기존에 있던 것을 구분해야 합니다. 새로 만든 것을 "되돌린다"는 것은 삭제이고, 원래 있던 것을 "되돌린다"는 것은 복원입니다. 둘을 똑같이 취급하면, 안전장치가 정상 앱을 삭제하게 됩니다.
  • 행동하기 전에 되돌리는 방법을 적어 두세요. 단계가 성공한 뒤에야 되돌리는 방법을 기록하면, 중간에 실패한 단계는 되돌릴 방법이 없습니다.
  • 내가 의존하는 요청의 응답을 무시하지 마세요. 무시된 "아니요" 한 번이 정상 앱을 실패한 배포로 바꿔 버렸습니다.

같은 날의 관련 수정으로 배포 직후 크래시하는 앱을 잡아내는 방법도 있습니다. 배포 쪽에서 실패가 발생했을 때의 대응은 docs의 배포 문제 해결 문서를 참고하세요.

Mythex · Pricing · AI로 무엇이든 만들기 · 웹사이트 및 앱 템플릿 · Mythex 비교 · AI 앱 개발 용어집 · 무료 AI 앱 개발 도구 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)