한 버킷에 주인이 둘이면, 마지막으로 apply한 쪽이 이긴다
S3 lifecycle 규칙 하나를 추가했더니 terraform apply가 실패했다. 원인은 같은 버킷의 lifecycle 설정을 두 리소스가 각자 소유한 구조. S3 lifecycle은 규칙 단위가 아니라 문서 단위라, 마지막 승자가 상대 규칙을 조용히 지운다.
- #인프라
- #Terraform
- #S3
- #AWS
- #장애대응
#장애대응
S3 lifecycle 규칙 하나를 추가했더니 terraform apply가 실패했다. 원인은 같은 버킷의 lifecycle 설정을 두 리소스가 각자 소유한 구조. S3 lifecycle은 규칙 단위가 아니라 문서 단위라, 마지막 승자가 상대 규칙을 조용히 지운다.
큐에 잡을 넣는 코드가 첫날부터 항상 실패하고 있었다. 에러는 삼켜졌고, 테스트는 목(mock) 덕분에 초록이었다. 콜론 한 글자가 기능 세 개를 조용히 죽인 이야기.
하루 사이 CRITICAL 알림 네 개가 쌓였다. 504, Prisma P2028, 어드민 500, 그리고 'DATABASE 서비스 다운'. RDS 지표를 먼저 열었더니 21시간 내내 CPU 최대 19.7%로 멀쩡했다. 느린 건 DB가 아니라 대서양을 스물다섯 번 건너는 왕복이었고, '다운' 알림은 헬스체크가 스스로 만든 것이었다.
staging에서 매일 뜨던 Google Play 404 알림. 소스를 끄면 조용해지지만, 그것과 실패 모드를 고치는 것은 다른 문제였다. 404는 재시도해도 소용없는 영구 오류인데 5xx와 한데 뭉쳐 재시도되고 있었다는 이야기.
배포마다 Sentry에 Prisma P2028 에러가 떨어졌다. 종료 순서를 고치러 들어갔다가, NestJS의 enableShutdownHooks와 graceful shutdown 라이브러리가 둘 다 SIGTERM을 잡아 종료 훅이 매번 두 번씩 실행되고 있었다는 걸 발견한 이야기.
certificate pinning 버그로 앱이 죽었을 때, 지우면 십 분이면 끝날 일을 살린 채 고치려다 몇 시간을 썼습니다. 장애 앞에서 복구보다 완벽한 수정을 택했던 날의 회고.
백그라운드 잡의 중복 실행을 막으려고 넣은 상태 가드가, 배포 중 프로세스가 죽자 잡을 '생성 중' 상태에 영구히 가둬버렸다. 잠금에는 반드시 풀리는 길이 함께 있어야 한다는 이야기.