← 개발 로그 목록

website: 마이그레이션 위험도 판단에서 UPDATE/DELETE DML이 빠져있던 걸 stage 실측 중 발견

/ 2분 분량 / 개발 로그

`cd.yml`의 마이그레이션 위험도 판단 스텝은 이번 배포에 새로 추가된 마이그레이션 파일을 grep으로 훑어서, `drop table`이나 `rename to` 같은 패턴이 있으면 "파괴적"으로 보고 자동 롤백 대신 사람에게 넘긴다. 그런데 검증 시나리오를 돌리면서 실제 마이그레이션 히스토리를 훑어보니 `V20260728115500` 파일이 `IN...

#320 시나리오 A~D를 stage에서 실측 검증하다가, 기존 마이그레이션 위험도 판단 로직이 DROP/RENAME만 보고 있다는 걸 다시 확인했다. 문제는 이 로직이 그동안 실제로 사각지대를 만들고 있었다는 것.

DROP/RENAME과 UPDATE/DELETE는 사실 성격이 다른 문제다. DROP/RENAME은 구버전 앱이 롤백된 뒤 사라진 컬럼을 찾다가 또 깨지는 "스키마 호환성" 문제고, UPDATE/DELETE는 앱 이미지만 되돌리는 롤백으로는 이미 실행된 데이터 변경을 되돌릴 수 없다는 "복구 불가능성" 문제다. 원인은 다르지만 결과적으로 둘 다 자동 롤백 전에 사람이 먼저 봐야 한다는 점은 같아서, 같은 destructive=true 플래그로 묶기로 했다.

grep 패턴을 추가할 때 신경 쓴 부분은 update라는 단어가 컬럼명에도 흔하게 들어간다는 거였다. updated_at, updated_by 같은 컬럼이 있으면 단순히 update만 찾아서는 오탐이 난다. 그래서 update[[:space:]]+[a-z0-9_]+[[:space:]]+set, delete[[:space:]]+from처럼 실제 DML 구문 구조까지 요구하도록 패턴을 짰다. INSERT는 계속 안전 취급으로 남겨뒀다 — 기존 행을 안 건드리니 시드 데이터 삽입 같은 용도로는 여전히 자유롭게 쓸 수 있어야 한다고 판단했다.

코드 변경 자체는 grep 패턴 한 줄 추가하는 정도로 작았지만(cd.yml에 12줄 추가), db-migration.md와 CI-CD.md에 이 판단 로직이 여전히 텍스트 휴리스틱이라는 한계와 왜 이렇게 묶었는지를 같이 적어뒀다. grep 기반 판별은 이 프로젝트가 컬럼 삭제·변경에 항상 쓰는 "테이블 재생성 패턴"에 기대는 방식이라, 이 컨벤션을 벗어난 파괴적 SQL은 여전히 놓칠 수 있다는 한계는 그대로 남는다. 실측 검증을 하지 않았으면 이 사각지대를 눈으로 확인할 기회도 없었을 것 같다 — 코드만 봐서는 "이론적으로 놓칠 수 있다" 정도로 넘어갔을 부분을, 실제 히스토리에 이미 해당 사례가 있다는 걸 보고 나서야 우선순위를 올려서 고쳤다.