상태 비교의 주의사항

상태 비교의 주의사항 (Caveats to state comparison)

state: 선택 메서드는 강력하지만 내부적으로 많은 복잡성을 가져요. 상태 비교를 활용하는 자동화 작업을 구성할 때 고려해야 할 사항들을 정리해 드릴게요.

출처: 문서

본문

state: 선택 메서드는 강력한 기능이고, 그 뒤에는 많은 복잡성이 있어요. 상태 비교를 활용하는 자동화 작업을 구성할 때 고려할 사항들을 아래에 정리했어요.

시드 (Seeds)

dbt는 1 MiB 미만 크기의 시드 파일에 대해 파일 해시를 저장해요. 이 시드들의 내용이 수정되면 그 시드는 state:modified에 포함돼요.

시드 파일이 1 MiB를 초과하면 dbt는 내용을 비교할 수 없고 그렇게 경고를 발생시켜요. 대신 dbt는 시드의 파일 경로만 사용해 변경을 감지해요. 파일 경로가 변경되었으면 시드가 state:modified에 포함되고, 아니면 포함되지 않아요.

tags 와 meta

tagsmeta의 변경은 리소스 레벨이든 YAML 파일의 개별 컬럼이든 수정으로 간주되지 않으며 state:modified를 트리거하지 않아요. dbt는 이 필드들을 리소스가 어떻게 materialize되는지에 영향을 주지 않기 때문에 metadata로만 취급해요. 이는 의도적인 동작이에요.

이것은 persist_docs가 활성화되었을 때만 수정으로 취급되는 description과는 달라요. 그 config가 materialization에 영향을 줄 수 있으므로 다른 모든 config 변경은 수정으로 간주돼요.

매크로 (Macros)

dbt는 변경된 매크로나 변경된 매크로에 의존하는 매크로에 의존하는 모든 리소스를 modified로 표시해요.

Vars

모델이 정의에 varenv_var를 사용한다면 dbt는 var 또는 env_var 값이 변경된 것 때문에 그 모델을 state:modified에 포함시키는 방식으로 그 계보를 식별할 수 없어요. 변수 변경이 다른 구성으로 이어진다면 모델이 modified로 표시될 가능성이 높아요.

테스트 (Tests)

dbt test -s state:modified 명령은 다음 둘을 모두 포함해요:

  • 새/수정된 리소스에서 선택하는 테스트
  • 그 자체가 새롭거나 수정된 테스트

리소스(모델, 시드, 스냅샷)를 추가하거나 변경하는 동시에 테스트를 추가하거나 변경하는 한, "단순한" 상태 선택으로 모든 것이 예상대로 동작해야 해요:

dbt run -s "state:modified"
dbt test -s "state:modified"

그러나 이는 복잡해질 수 있어요. 기반 모델을 수정하지 않고 새 테스트를 추가하거나, 새 모델과 오래되고 수정되지 않은 모델 둘 다에서 선택하는 테스트를 추가하면, 모델을 먼저 실행하지 않고 테스트해야 할 수 있어요.

테스트할 때 업스트림 참조를 defer할 수 있어요. 예를 들어 테스트가 현재 환경에 데이터베이스 객체로 존재하지 않는 모델에서 선택한다면, dbt는 state 매니페스트에 정의된 다른 환경을 대신 봐요. 이를 통해 쿼리 실패 위험 없이 "단순한" 상태 선택을 사용할 수 있지만, 부모가 여러 개인 테스트에는 놀라운 결과가 있을 수 있어요. 예를 들어 수정된 모델 하나와 수정되지 않은 모델 하나에 의존하는 relationships 테스트가 있다면, 그 테스트 쿼리는 두 개의 서로 다른 환경 "에 걸쳐" 데이터에서 선택해요. 개발과 CI에서 데이터를 제한하거나 샘플링한다면, 불일치 가능성이 크다는 점을 알고도 참조 무결성을 테스트하는 것이 말이 안 될 수 있어요.

relationships 테스트나 데이터 테스트를 자주 사용하거나, 기반 모델을 수정하지 않고 테스트를 자주 추가한다면 CI 작업의 선택 기준을 조정하는 것을 고려해 보세요. 예를 들어:

dbt run -s "state:modified"
dbt test -s "state:modified" --exclude "test_name:relationships"

manifest.json 덮어쓰기 (Overwrites the manifest.json)

dbt는 파싱 중 manifest.json 파일을 덮어써요. 즉 target/ 디렉터리에서 --state를 참조하면 저장된 매니페스트를 찾을 수 없다는 경고가 발생할 수 있어요.

Saved manifest not found error — 다음 작업 실행 중 dbt는 이 문제로 이어지는 일련의 단계를 따릅니다. 먼저 변경 감지에 사용되기 전에 target/manifest.json을 덮어씁니다. 그런 다음 dbt가 변경을 감지하기 위해 target/manifest.json을 다시 읽으려고 하면, 이전 상태가 이미 덮어써졌기 때문에 찾지 못합니다.

--deferstate:modified 같은 상태 의존 기능과 함께 --state--target-path를 같은 경로로 설정하지 마세요. 비멱등적(non-idempotent) 동작으로 이어져 예상대로 작동하지 않을 수 있어요.

권장사항 (Recommendation) — dbt가 변경 감지 전에 manifest.json을 덮어쓰는 것을 막으려면 다음 방법 중 하나로 워크플로를 업데이트하세요:

  • dbt가 target/ 폴더에 manifest.json을 생성한 후 전용 폴더(예: state/)로 옮기기. 이렇게 하면 방금 덮어쓴 버전과 현재 상태를 비교하는 대신 dbt가 올바른 저장 상태를 참조하게 돼요. 또한 --state--target-path를 같은 위치로 설정해 비멱등적 동작을 일으키는 문제도 피할 수 있어요.
  • 빌드 단계(dbt가 target/manifest.json을 생성할 곳)에서 또는 작업 실행 중 덮어쓰기 전에 매니페스트를 다른 --target-path에 쓰기. 이렇게 하면 방금 덮어쓴 버전과 현재 상태를 비교하는 대신 dbt가 변경을 감지할 수 있어요.
  • 재현 단계에서 --no-write-json 플래그 전달하기: dbt ls --no-write-json --select state:modified --state target:.

거짓 양성 (False positives)

(dbt v1.9 이상) env-aware 로직 때문에 state:modified 선택 중 거짓 양성을 줄이려면 state_modified_compare_more_unrendered_values 동작 플래그를 true로 설정할 수 있어요. state 디렉터리는 dbt v1.9 이상 또는 dbt v1 Latest release track으로 빌드해야 하고, dbt_project.yml 안에서 state_modified_compare_more_unrendered_values를 true로 설정해야 해요.

state 디렉터리가 더 오래된 dbt 버전으로 빌드되었거나 state_modified_compare_more_unrendered_values 동작 변경 플래그가 설정되지 않았거나 false로 설정된 경우, state:modified와의 상태 비교 중 거짓 양성을 피하려면 state 디렉터리를 다시 빌드해야 해요.

예약된 작업 (Scheduled jobs)

state:modifiedstate:modified+는 프로젝트 코드, 구성, 또는 매니페스트 관련 메타데이터의 변경만 감지해요. 새 행이 소스 테이블에 도착하는 것 같은 데이터 자체의 변경은 감지하지 않아요. dbt가 지연된 매니페스트가 마지막으로 생성된 이후 코드나 구성 변경을 감지하지 못하면 작업은 모델을 빌드하지 않고 성공해요. 이는 예상된 동작이에요.

작업이 코드 변경과 무관하게 모든 예약 실행에서 모델을 빌드해야 한다면, 그 작업에서 state:modified 셀렉터를 제거하세요. 주어진 pull request나 merge에서 변경된 것만 빌드하려는 CI 또는 merge 작업에만 사용하세요.

마지막 메모 (Final note)

상태 비교는 복잡해요. 우리는 모든 구성 옵션 사이에서 궁극적인 일관성에 도달하고, 사용자에게 기대하는 수정된 리소스들만 신뢰성 있게 반환할 수 있는 제어를 제공하기를 바라요. 더 알고 싶다면 dbt 리포지토리의 "state" 태그가 달린 공개 이슈를 읽어 보세요.

더 알아보기 (Learn more)