ALEMBIC_MIGRATION_DRIFT_resolution_20260523
- 문서 작성자: 덱스PM
- 문서 오너: 덱스PM
- 작성일: 2026-05-23
- 연관 이슈:
ALEMBIC_MIGRATION_DRIFT_20260523 - 상태: Draft
개요
MMX api의 Alembic 상태를 정밀 점검한 결과, 최초 장애는 Cloud Run startup 시 alembic upgrade head가 multiple heads 때문에 실패한 것이었고, 그 뒤에도 모델 메타데이터와 실제 DB 스키마 사이에 drift가 남아 있었다. 본 문서는 그 drift를 어떻게 분류하고, 어떤 판단으로 수정했는지 상세히 기록한다.
1. 최초 장애 원인
Cloud Run mmx-api 컨테이너는 entrypoint에서 아래 순서로 동작한다.
alembic upgrade headuvicorn main:app
문제는 head가 1개가 아니라 2개였다는 점이다.
9d04ce19b61eb7c9d1e2f3a4
이 상태에서는 Alembic이 단일 upgrade 경로를 확정하지 못해 startup migration에서 중단되었고, 결과적으로 Cloud Run revision이 healthy 상태로 올라오지 못했다.
조치
- merge migration 추가
c1d2e3f4a5b6_merge_project_document_release_head.py
- 이후
mmx-api-00076-npw배포 성공 확인
2. 후속 정밀 점검에서 확인된 drift
head 충돌을 해소한 뒤 alembic check를 실행하자 다수의 new upgrade operations가 검출되었다. 이 시점에서 문제는 단순한 head 충돌이 아니라, 장기간 누적된 모델-스키마 drift라는 것이 명확해졌다.
주요 범주는 아래와 같았다.
2.1 과거 임시 테이블 / 잔재성 스키마
deep_temp_tbl
DB에는 존재하지만 ORM 메타데이터에는 없어 Alembic이 제거 대상으로 인식했다.
2.2 모델 누락
scenarios.thumbnail_idscenarios.shortcut_vid_idscenarios.trailer_id
과거 migration에는 존재했지만 현재 Scenario 모델 정의에는 빠져 있어, Alembic이 삭제 대상으로 인식했다.
2.3 nullable / default 정합성 차이
users.google_subusers.emailusers.nameusers.last_login_atusers.is_testerusers.tokensgame_status.genre_tagsgame_status.created_atgame_status.updated_atmedia.created_at
초기/복구 migration에서 만들어진 nullable/default와 현재 모델 정책이 완전히 일치하지 않았다.
2.4 인덱스 / 제약조건 naming drift
game_statusproject_document_commentsproject_document_releasesstudio_scenariosusers.username
기존 migration은 수동 index name을 사용했고, ORM은 기본 naming 또는 다른 선언 방식을 기대해 drift가 발생했다.
3. 분류와 판단
3.1 deep_temp_tbl
즉시 제거하지 않았다.
이유:
- 별도 작업 흔적(
deepSeek_20260521_job.md)이 존재했다. - migration 그래프 안에 이미 공식 revision으로 편입되어 있었다.
- 운영 DB에 존재하는 테이블을 의미 확인 없이 제거하면 2차 장애 위험이 있다.
조치:
DeepTempORM 모델을 추가해 Alembic 메타데이터에 포함시켰다.
3.2 scenarios.*_id
즉시 삭제하지 않았다.
이유:
- 과거 migration
c4a8e1f02b3d_alpha_schema_complete.py에서 명시적으로 도입되었다. game_status,schemas_game.py쪽에서도 미디어 관련 구조가 이미 사용 흔적을 남기고 있었다.
조치:
Scenario모델에thumbnail_id,shortcut_vid_id,trailer_id를 다시 반영했다.
3.3 nullable / default drift
DB를 현재 모델/서비스 정책 쪽으로 정렬했다.
판단 근거:
- 인증 코드상
User는 nullable 가능한 필드를 자연스럽게 다루고 있었다. - 현재 제품 구조에서
google_sub,email,name,last_login_at는 스키마 레벨에서 절대 NOT NULL이어야 한다는 강한 근거가 부족했다. - 반대로
is_tester,tokens,game_status일부,media.created_at는 현재 모델 기준 NOT NULL이 더 일관적이었다.
조치:
- 정합화 migration 추가
f4e5d6c7b8a9_align_alembic_schema_with_models.py
3.4 인덱스 / 제약조건 drift
운영 DB의 기존 명명 규칙을 존중하는 방향으로 ORM 선언을 맞췄다.
판단 근거:
- 이 단계에서 DB 인덱스를 재명명하는 것보다, 모델 쪽에 명시적
Index(...)/UniqueConstraint(...)를 부여해 autogenerate drift를 없애는 편이 안전하다. - 사용자 요청은 “완벽한 마감”이지, 불필요한 물리 스키마 재작성 자체가 목적은 아니다.
조치:
ProjectDocumentComment에idx_project_document_comments_document_key반영ProjectDocumentRelease에 legacy index 3개 및 unique constraint 명시 반영StudioScenario에 legacy index 2개 반영GameStatus에 legacy index 3개 반영User.username는 unique column 표현 대신idx_users_username명시 인덱스로 정렬
4. 실제 수정 파일
API / Alembic
api/alembic/versions/c1d2e3f4a5b6_merge_project_document_release_head.pyapi/alembic/versions/f4e5d6c7b8a9_align_alembic_schema_with_models.py
API / Models
api/models/__init__.pyapi/models/game_models.pyapi/models/game_status.pyapi/models/project_document_comment.pyapi/models/project_document_release.pyapi/models/studio_scenario.pyapi/models/temp.pyapi/models/user.py
Project Documents
www/public/project_document/issues/ALEMBIC_MIGRATION_DRIFT_20260523.mdwww/public/project_document/issues/index.htmlwww/public/project_document/reports/ALEMBIC_MIGRATION_DRIFT_resolution_20260523.md
5. 검증 결과
정리 후 아래를 확인했다.
alembic heads- 단일 head:
f4e5d6c7b8a9
- 단일 head:
alembic current- 현재 DB revision이 동일 head를 가리킴
alembic checkNo new upgrade operations detected.
- Python compile
- 관련 model/migration 파일 컴파일 통과
6. 남은 관찰 사항
alembic check는 통과했지만, 아래 경고가 남아 있다.
media↔scenarios사이의 FK cycle warning
이 경고는 현재 즉시 drift를 발생시키지는 않지만, 향후 SQLAlchemy/Alembic 버전 변화에 따라 더 엄격하게 다뤄질 수 있다. 따라서 운영 규칙 문서에는 아래를 포함해야 한다.
- 순환 FK가 생기지 않도록 신규 모델 설계 시 주의한다.
- 기존 cycle은 별도 구조 개선 과제로 분리 검토한다.
alembic checkclean과 warning-free는 같은 의미가 아님을 명시한다.
7. 결론
이 이슈의 본질은 단순한 배포 실수가 아니라, 누적된 migration hygiene 부채였다.
최종적으로:
- multiple heads는 해소되었고
- drift 항목은 분류/정리되었으며
alembic check기준 clean 상태를 확보했다
따라서 Alembic migration 관점에서 이번 장애의 직접 원인과 누적 drift는 모두 운영 가능한 수준으로 정리되었다.