본문으로 건너뛰기

Spring Data Fragment 스캔 CrashLoop

증상

백엔드 포드가 시작 중 크래시 루프에 빠지고, 리포지토리 Bean 오류가 No property 'filter' found for type ... 같은 쿼리 파생 메시지로 끝납니다.

과거 사고는 lumie-backend/app/src/test/java/com/lumie/app/ApplicationContextLoadsTest.java의 현재 스모크 테스트 주석에 남아 있습니다. 이 주석은 리포지토리 인터페이스 패키지 밖에 있던 StaffRepositoryCustomImpl를 가리킵니다.

가능한 원인

Spring Data가 커스텀 fragment 구현을 찾지 못하면 리포지토리 메서드는 메서드 이름 기반 쿼리 파생으로 넘어갑니다.

이는 일반적으로 다음과 같은 경우에 발생합니다.

  • 조각 인터페이스는 domain/repository 아래에 있습니다.
  • 구현은 adapter/out/persistence에 따라 진행됩니다.
  • 구현이 스캔된 패키지 경로에 있지도 않고 Spring Bean으로 노출되지도 않습니다.

진단

필드 매핑 문제가 아닌 Spring 데이터 폴백 시퀀스로 스택 추적을 읽습니다.

  1. 파서가 저장소 메서드 이름을 딴 속성이 누락되었다고 불평하는 경우 조각 해결이 이미 실패한 것입니다.
  2. 커스텀 구현이 리포지토리 인터페이스와 같은 패키지 하위 트리에 있는지 확인합니다.
  3. 구현이 Spring Bean인지 확인합니다.
  4. 모듈 @DataJpaTest 슬라이스뿐만 아니라 전체 컨텍스트 스모크 테스트를 실행합니다.

현재 회귀 가드는 다음과 같습니다.

  • lumie-backend/app/src/test/java/com/lumie/app/ApplicationContextLoadsTest.java
  • lumie-backend/app/src/test/java/com/lumie/app/FullContextTestBase.java

이러한 테스트는 특히 더 좁은 조각이 모놀리스 전체에 걸쳐 전체 저장소-프록시 구성을 실행하지 않았기 때문에 존재합니다.

수정

  • 크로스 패키지 조각 구현에 @Component를 추가하거나
  • 구현을 저장소 인터페이스 패키지 하위 트리로 이동하거나
  • 아키텍처에 분할 패키지가 필요한 경우 저장소 구현 검색을 명시적으로 확대합니다.

2026년 사고에서는 임시방편으로 첫 번째 옵션을 사용한 다음 전체 컨텍스트 스모크 테스트를 추가하여 동일한 실패로 인해 프로덕션 대신 CI가 차단되었습니다.

예방

  • 커스텀 리포지토리 fragment를 단순한 persistence 세부 사항이 아니라 부팅 시 wiring 위험으로 처리합니다.
  • 기본 테스트 그래프에 하나 이상의 @SpringBootTest(classes = LumieApplication.class) 스모크 테스트를 유지합니다.
  • 프래그먼트 구현이 패키지 경계를 넘을 때 규칙에 의존하는 대신 검색 규칙을 명시적으로 만듭니다.

원본 사고 세부사항

2026년 5월 21일 원본 사고는 Spring Data repository fragment discovery 때문에 production CrashLoopBackOff가 발생한 사건입니다. 좁은 repository-slice test는 전체 monolith repository graph를 만들지 않았기 때문에 이를 놓쳤습니다.

세부사항
증상application이 traffic을 받기 전에 startup 실패
Exception class원본 기록의 PropertyReferenceException
직접 root causeSpring Data가 기대한 위치에서 fragment implementation을 발견하지 못했습니다
Stopgapcross-package fragment implementation에 @Component 추가
Regression guardfull application context smoke test

진단 함정은 Spring Data가 fragment implementation 누락을 derived-query method처럼 해석할 수 있다는 점입니다. 그래서 마지막 exception은 property-name 문제처럼 보이지만, 실제 문제는 repository fragment wiring입니다.

원본 기록은 기존 test가 왜 놓쳤는지도 설명합니다.

기존 test type놓친 이유
per-module @DataJpaTest slicemodule-local repository만 로드했습니다
routing datasource integration test의도적으로 빈 repository package를 사용했습니다
web-layer testJPA layer를 mock하거나 건너뛰었습니다

보존된 예방책은 monolith 전반의 repository proxy construction을 실행하는 full @SpringBootTest(classes = LumieApplication.class) context test입니다.