Skip to content

fix(infra): compose·.env.example 이 settings.py 기본값을 덮어쓰지 않게 - #248

Merged
i3months merged 1 commit into
devfrom
fix/compose-shadowing-settings-defaults
Sep 25, 2026
Merged

i3months merged 1 commit into
devfrom
fix/compose-shadowing-settings-defaults

Conversation

@i3months

Copy link
Copy Markdown
Member

요약

PR #246 의 핵심 변경이 운영에 도달하지 못하고 있었습니다. 그 원인을 구조적으로 막습니다.

발견 경위

#246 이 머지·배포된 뒤, 9/21부터 FAILED 로 남아 있던 웹 이력서를 새 재분석 API 로 복구하려 했습니다. 또 실패했습니다.

11:41:06  analyze.document  92577ms  FAILED  Request timed out.
11:42:39  analyze.document  92160ms  FAILED  Request timed out.

92초 = 30초 × 3. #246 에서 60초로 올렸는데 30초가 그대로 살아 있었습니다.

settings.py          llm_pro_timeout_sec = 60.0      ← #246 에서 고침
docker-compose.yml   ${LLM_PRO_TIMEOUT_SEC:-30.0}    ← 여기가 이김
운영 .env            LLM_PRO_TIMEOUT_SEC=30.0        ← 이게 최종

운영 .env 를 60.0 으로 고치고 다시 돌리니:

30초 60초
analyze.document 4회 전부 실패 (92초) 성공 (37.4초)

실제로 37.4초가 필요했습니다. 30초로는 구조적으로 불가능했고, 그걸 고친 PR 이 조용히 무효가 되어 있었습니다. 사람 눈으로는 잡을 수 없는 종류의 사고입니다.

ai/CLAUDE.md §9 는 "settings.py 가 single source of truth" 라고 적혀 있지만, ai 서비스 32개 키 중 24개가 compose 에 기본값을 중복으로 갖고 있었습니다.

변경 내용

1. docker-compose.yml — ai 환경변수를 리스트 형태로 바꾸고 튜닝 값은 이름만 적어 전달만 합니다.

- LLM_PRO_TIMEOUT_SEC          # .env 에 있으면 그 값, 없으면 코드 기본값

미설정이 빈 문자열이 아니라 진짜 미설정으로 전달되는지 서버에서 docker compose run 으로 실측 확인했습니다 (${VAR:-} 였다면 빈 문자열이 코드 기본값을 덮습니다).

값을 유지한 것은 settings.py 가 알 수 없는 것들뿐입니다 — 컨테이너 호스트명(http://backend:38010), MINIO_ROOT_USER→S3_ACCESS_KEY 이름 변환, 비면 로컬 기동이 막히는 개발용 기본값.

2. .env.example — 코드 기본값과 같은 17개 키를 주석 처리했습니다. deploy-app.yml 이 KEY=값 줄을 운영 .env 에 영구 복사하므로, 여기 적는 순간 코드 기본값이 영원히 가려집니다.

3. EMBEDDING_PROVIDER=gemini 추가 — 조사 중 발견한 별개 지뢰입니다. 루트 .env.example 에 이 키가 아예 없어서, 신규 배포는 코드 기본값 mock 으로 뜹니다. 즉 가짜(해시 기반) 임베딩으로 조용히 기동하고 RAG 검색이 무의미해집니다. 현재 운영이 정상인 건 누군가 .env 에 수동으로 넣어둔 덕입니다.

4. ai/tests/test_compose_defaults.py — CI 가드. 세 가지를 막습니다:

  • compose 가 settings.py 기본값을 중복 선언
  • ${VAR:-} 빈 문자열 fallback
  • settings.py 에 없는 키를 전달 (오타·죽은 설정)

가드가 실제로 잡는지 일부러 되돌려 확인했습니다 — 3건 모두 검출.

5. docs/environment.md §0 — 우선순위와 예외 규칙 명시.

테스트

  • uv run pytest 416 passed, black/flake8 clean
  • 가드 회귀 검출 확인 (중복 기본값 / 빈 fallback / 오타 키)
  • 서버에서 docker compose config --env-file .env 로 새 compose 해석 결과 대조 — 의도한 차이만 발생

⚠️ 머지 후 필요한 운영 작업 (이 PR 만으로는 안 끝납니다)

운영 .env 는 deploy 가 추가만 하고 삭제하지 않으므로 낡은 값이 그대로 남습니다. 배포 후 아래를 손으로 지워야 코드 기본값이 실제로 삽니다:

키 운영 .env 코드 비고
DEEPGRAM_TIMEOUT_SEC 30 20 #244 의 20초가 아직 안 먹고 있음
그 외 16개 코드와 동일 — 지워도 동작 불변, 향후 코드 변경이 도달하게 됨

EMBEDDING_PROVIDER=gemini 와 시크릿 4개는 유지해야 합니다.

⚠️ 순서 주의: compose 배포 전에 .env 를 지우면 구 compose 의 :-30.0 이 되살아나 오히려 후퇴합니다. 반드시 머지→배포→정리 순서로 진행해야 합니다.

리뷰어 체크포인트

  • COMPOSE_OWNED 화이트리스트(8개)가 적절한지 — 여기 있는 키만 compose 가 기본값을 가집니다.
  • backend·realtime 서비스에도 같은 패턴이 있는지 확인하지 않았습니다. ai 만 손댔습니다.
  • .env.example 주석 처리로 신규 배포의 기본값이 바뀝니다(코드 기본값으로). 기존 운영은 영향 없습니다.

🤖 Generated with Claude Code

PR #246 에서 LLM_PRO_TIMEOUT_SEC 를 30→60 으로 올렸는데 운영에 도달하지 못했다.
docker-compose.yml 의 `${LLM_PRO_TIMEOUT_SEC:-30.0}` 과 운영 .env 의 30.0 이
코드 기본값을 덮고 있었다. 그래서 웹 이력서 재분석이 92초(=30초×3) 만에 또
타임아웃으로 죽었다 — 60초를 실제로 적용하니 37.4초에 성공했다. 30초로는
구조적으로 불가능한 작업이었고, 그걸 고친 PR 이 조용히 무효가 되어 있었다.

기본값이 세 군데(settings.py / compose / .env)에 흩어져 있고 코드가 제일 약한
구조가 원인이다. ai 서비스 32개 키 중 24개가 compose 에 기본값을 중복으로
갖고 있었다.

- docker-compose.yml: ai 환경변수를 리스트 형태로 바꾸고, 튜닝 값은 이름만 적어
  **전달만** 한다(`- LLM_PRO_TIMEOUT_SEC`). .env 에 있으면 그 값이 가고 없으면
  아무것도 안 가서 코드 기본값이 산다. 미설정이 진짜 미설정으로 전달되는 것은
  서버에서 `docker compose run` 으로 실측 확인했다(빈 문자열이 아님).
  값을 유지한 것은 컨테이너 토폴로지·이름 변환·로컬 기동용 기본값뿐이다.
- .env.example: 코드 기본값과 같은 17개 키를 주석 처리. deploy-app.yml 이
  `KEY=값` 줄을 운영 .env 에 영구 복사하므로, 여기 적는 순간 코드 기본값이
  영원히 가려진다.
- .env.example 에 EMBEDDING_PROVIDER=gemini 추가. 코드 기본값이 mock 이라
  신규 배포가 **가짜 임베딩으로 조용히 뜨는** 지뢰였다(현재 운영은 누군가
  .env 에 수동으로 넣어둔 덕에 정상).
- ai/tests/test_compose_defaults.py: 중복 기본값·빈 문자열 fallback·오타 키를
  CI 에서 차단. 세 가지 회귀를 실제로 잡는지 확인했다.
- docs/environment.md §0 에 우선순위와 예외 규칙 명시.
@i3months
i3months merged commit 7b5c334 into dev Sep 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant