Migration Script, 한 번 더 돌려도 괜찮아?
멱등성 없는 migration script 가 새벽 장애를 부른다. 체크리스트 정리.
왜 갑자기 이 얘기
최근 hotfix 배포 중 migration 을 두 번 돌렸다. 결과는 duplicate row. 스크립트 자체는 테스트를 통과했지만 멱등성 보장 코드는 없었다. 새벽 두 시였고, 롤백에 40분 걸렸다.
사실 “한 번만 실행”은 보장이 아니다. CI 재시도, 수동 재실행, 파이프라인 타임아웃 재기동 — 실수로 두 번 실행될 경로는 생각보다 많다.
멱등성 체크리스트
스키마 변경
ADD COLUMN IF NOT EXISTS/CREATE TABLE IF NOT EXISTS사용 여부DROP계열은 반드시IF EXISTS. 없으면 두 번째 실행 즉시 에러- 인덱스 생성:
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_name ...
데이터 삽입/수정
INSERT INTO ... ON CONFLICT DO NOTHING또는UPSERT- 순수
INSERT는 99% 멱등하지 않음 - 보정값 계산 (예:
amount * 1.1) 은 WHERE 절로 이미 보정된 행 제외 필수
실행 기록
migrations테이블에 checksum + 실행 시각 남기기- 이미 실행된 hash 면 early return. Flyway·Liquibase 가 이걸 기본으로 해주는데 직접 짜면 빠뜨리기 쉽다
- 기록 없이 “파일명으로 판단” 은 파일 수정 시 무력화됨
외부 호출 포함 스크립트
- Stripe charge, 이메일 발송 등 side-effect 가 있으면 별도 플래그 컬럼 (
notified_at,charged_at) 으로 guard - 멱등 키(idempotency key) 를 API 에 명시적으로 넘기거나, 넘길 수 없으면 호출 전에 DB 에서 실행 여부 먼저 확인
트랜잭션 범위
- DDL 과 DML 을 같은 트랜잭션 안에 넣으면 PostgreSQL 에서는 괜찮지만 MySQL 에서는 DDL 이 암묵적 commit. 섞지 마라
- 긴 migration 은 배치로 쪼개고, 배치 단위마다 checkpoint 기록
다음 한 가지
다음 PR 부터 migration script 하단에 주석 한 줄 추가: -- idempotent: yes/no, reason: .... 작성자가 직접 선언하게 만들면 리뷰어 눈에 바로 들어온다.
🛒 이 글과 어울리는 추천 상품
위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.