Skip to content

Conversation

@Do-oya
Copy link
Member

@Do-oya Do-oya commented Oct 30, 2025

📌 Issue


🧐 현재 상황

  • Elasticsearch 게시글 검색에 Redis 도입

🎯 목표

  • Elasticsearch 게시글 검색에 Redis 도입

🛠 작업 내용

  • 작업 할 내용을 입력해주세요.

  • Elasticsearch 게시글 검색에 Redis 도입

  • 테스트 작성


🚀 기타 사항

  • 추가적인 내용을 작성해주세요.(참고 자료, 협업 내용)

Summary by CodeRabbit

  • New Features

    • 게시글 검색 결과 Redis 기반 캐시 추가(기본 TTL 3분)로 응답 속도 향상
    • 도메인 이벤트 발생 시 자동 캐시 무효화(생성·수정·발행·숨김·삭제)
  • Tests

    • 캐시 동작 및 무효화 검증 테스트 추가
    • 성능 벤치마크 및 시뮬레이션 시나리오 업데이트
  • Chores

    • 캐시 설정 바인딩 및 CI에 Redis 서비스 추가, 관련 문서 설명 보강

- jmhJar 작업에 Zip64 지원 추가하여 대용량 JMH Jar 패키징 가능
- 특정 환경에서 발생할 수 있는 압축 파일 크기 제한 문제 해결
- JMH 성능 테스트 결과의 안정적 배포 지원을 목표
- RedisConfig에 @EnableConfigurationProperties 추가하여 PostSearchCacheProperties 사용 가능하도록 설정
- Redis 관련 설정 확장성을 높이고 구성 관리 효율성 강화
- Cache 관련 속성 정의 및 유연한 설정 적용 기반 마련
- 검색 결과 캐시 TTL(time-to-live)을 설정할 수 있는 PostSearchCacheProperties 클래스 추가
- 기본 TTL 값은 3분으로 설정
- Spring Boot의 @ConfigurationProperties 사용으로 유연한 구성 지원
- 캐시 TTL 설정을 별도 속성으로 분리하여 유지보수성 강화 및 확장성 확보
- 게시글 검색 결과 캐시에 대한 Redis 기반 구현 클래스 추가
- PostSearchCacheRepository 인터페이스 구현하여 통합 가능성 제공
- 검색 키워드와 페이징 정보를 기반으로 캐시 조회 및 저장 처리 지원
- 검색 캐시 전체 삭제 기능 제공으로 관리 용이성 향상
- 콘텐츠 직렬화/역직렬화 오류 처리 로직 추가로 안정성 강화
- TTL 설정을 사용하여 캐시 만료 시간 관리
- 게시글 관련 이벤트(PostCreated, PostUpdated, PostPublished, PostHidden, PostDeleted) 처리하여 검색 캐시를 자동으로 무효화하는 PostSearchCacheEventHandler 추가
- PostSearchCacheRepository.evictAll 호출로 캐시 무효화 처리
- 이벤트 비동기 처리와 트랜잭션 커밋 이후 실행 보장으로 성능 및 데이터 일관성 강화
- PostSearchCacheEvictCommand를 통한 수동 캐시 무효화 지원으로 유연성 제공

test(cache): add unit tests for PostSearchCacheEventHandler

- 게시글 이벤트(PostCreated, PostUpdated 등) 처리 시 캐시 무효화 동작 검증 테스트 추가
- PostSearchCacheEvictCommand 처리에 대한 테스트로 전체 캐시 초기화 로직의 신뢰성 강화
- 게시글 검색 요청 시 Redis 캐시를 조회하고 없을 경우 검색 결과를 캐싱하는 로직 추가
- PostQueryService에 검색 캐싱 관련 fetchAndCacheSearchResults 메서드 구현
- Redis 캐시에 실패하더라도 검색 흐름에 영향을 주지 않도록 기록만 남기도록 설계
- PostFinderTest에 Redis 캐싱 기능을 검증하는 테스트 케이스 추가
- 기존 Elasticsearch 검색에 Redis 캐시 계층 추가로 검색 성능 최적화
- 검색 시나리오별 벤치마킹 클래스를 분리하며 확장 가능한 상태 관리 설계 추가
- AbstractBenchmarkState 추상화로 Cold, Cached, Database SearchState에 공통 로직 재사용
- ColdSearchState에서 캐시 초기화 로직 추가로 콜드 스타트 성능 측정 용이성 제공
- CachedSearchState에서 캐시 적중 상태 벤치마킹 지원
- BenchmarkState의 중복 제거 및 분리로 코드 가독성과 유지보수성 강화
- Elasticsearch 및 데이터베이스 호출의 성능 비교를 위한 명확한 벤치마크 항목 정의
…tates

- Gatling 시뮬레이션에 cold cache와 warm cache 상태 추가로 성능 테스트 시나리오 확장
- coldKeyword와 hotKeyword 분리로 캐시되지 않은 상태와 이미 적중된 상태의 검색 성능 측정 가능
- es-cache-warm 및 es-cache-hit 액션 추가로 엘라스틱서치 캐시 시뮬레이션 개선
- dbSearch와 esSearch 호출 흐름에 캐시 관련 단계 추가로 테스트 정확성 강화
- 캐시 초기화부터 캐시 적중까지의 전 과정 성능 테스트 시나리오 제공
- Elasticsearch 검색 결과를 Redis에 캐싱하는 기능 설명 추가
- 검색 응답 지연을 줄이기 위해 3분 TTL을 적용하는 방식 명시
- 프로젝트 주요 기능 목록에 검색 캐시 항목 추가하여 명확성 강화
@Do-oya Do-oya self-assigned this Oct 30, 2025
@Do-oya Do-oya added ✨ Feature 기능 개발 ✅ Test test 관련(storybook, jest...) labels Oct 30, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 30, 2025

Walkthrough

Elasticsearch 게시글 검색 결과에 Redis 기반 캐시를 도입했습니다. 캐시 인터페이스와 Redis 구현체, TTL 설정, 캐시 무효화 이벤트 핸들러, PostQueryService의 캐시 적용, 벤치마크/시뮬레이션 및 테스트와 CI(Redis 서비스) 구성이 추가되었습니다.

Changes

Cohort / File(s) Summary
캐시 인터페이스 및 설정
src/main/java/dooya/see/application/post/required/PostSearchCacheRepository.java, src/main/java/dooya/see/adapter/integration/cache/config/PostSearchCacheProperties.java
검색 캐시 계약 인터페이스 추가 및 기본 TTL(3분)을 갖는 설정 프로퍼티 클래스 추가
Redis 캐시 구현 및 구성
src/main/java/dooya/see/adapter/integration/cache/RedisPostSearchCacheRepository.java, src/main/java/dooya/see/adapter/integration/cache/config/RedisConfig.java
RedisTemplate + Jackson 기반 캐시 저장소 구현 추가(키 정규화, JSON 직렬화/역직렬화, TTL 지원) 및 설정 바인딩 등록(@EnableConfigurationProperties)
서비스 레이어 캐시 적용
src/main/java/dooya/see/application/post/PostQueryService.java
searchPosts에 캐시 조회/저장 로직 추가, 캐시 저장 실패 시 로깅 처리(서비스 결과 영향 없음)
캐시 무효화 이벤트 핸들러
src/main/java/dooya/see/application/post/PostSearchCacheEventHandler.java
게시물 생명주기 이벤트 및 명시적 캐시 무효화 명령에 대한 비동기 AFTER_COMMIT 리스너 추가(현재는 전체 캐시 무효화)
벤치마크·시뮬레이션 변경
src/gatling/scala/dooya/see/search/PostSearchSimulation.scala, src/jmh/java/dooya/see/benchmark/PostSearchBenchmark.java, build.gradle.kts
핫/콜드 키워드 분리, 캐시 워밍·히트 시나리오 추가, 벤치마크 상태 리팩토링 및 jmhJar Zip 설정(isZip64=true) 추가
테스트 변경/추가
src/test/java/dooya/see/application/post/PostSearchCacheEventHandlerTest.java, src/test/java/dooya/see/application/post/provided/PostFinderTest.java
이벤트 핸들러 단위 테스트 추가 및 PostFinder 통합 테스트에 캐시 레포지토리 주입·초기화 및 검증 추가
CI 및 문서
.github/workflows/ci.yml, README.md
CI에 Redis 서비스 추가 및 준비 검사에 Redis 포함, README에 Elasticsearch 검색 결과 캐싱(3분 TTL) 문구 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Service as PostQueryService
    participant Cache as PostSearchCacheRepository
    participant ES as Elasticsearch

    Client->>Service: searchPosts(keyword, pageable)
    Service->>Cache: find(keyword, pageable)
    alt 캐시 히트
        Cache-->>Service: Optional[Page]
        Service-->>Client: 반환(캐시)
    else 캐시 미스
        Service->>ES: search request
        ES-->>Service: Page<PostSearchResult>
        Service->>Cache: save(keyword, pageable, page)
        Cache-->>Service: ack
        Service-->>Client: 반환(검색결과)
    end
Loading
sequenceDiagram
    participant Post as Post Lifecycle Event
    participant Handler as PostSearchCacheEventHandler
    participant Cache as PostSearchCacheRepository

    Post->>Handler: PostCreated/Updated/Published/Hidden/Deleted
    note over Handler: @TransactionalEventListener(AFTER_COMMIT)\n@Async("applicationTaskExecutor")
    Handler->>Handler: evict(source, postId)
    Handler->>Cache: evictAll()
    Cache-->>Handler: completed
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • 주의 영역:
    • PostQueryService.java: 캐시 폴백 및 예외 처리(캐시 실패시 검색 흐름 보장) 확인
    • RedisPostSearchCacheRepository.java: 직렬화/역직렬화 예외 처리와 키 생성(페이지네이션 포함) 검증
    • PostSearchCacheEventHandler.java: 모든 이벤트에서 전체 캐시를 evictAll() 하는 전략 의도 확인
    • 벤치마크·시뮬레이션 변경: 핫/콜드 흐름이 실제 시나리오와 일치하는지 검토

Possibly related PRs

Suggested labels

⚙ Setting

Poem

🐇 깡충 깡충, 키워드를 품에 안고,
Redis에 잠시 쉬게 두었네.
워밍 한 번이면 속도 훌쩍,
게시물 바뀌면 깨끗이 쓸어내요,
토끼가 속삭이듯 빠르게 달려가요 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.52% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed PR 제목 "Elasticsearch 게시글 검색에 Redis 도입"은 변경 사항의 주요 목표를 명확하게 반영하고 있습니다. 제목은 이 PR의 핵심 기능인 Redis 캐시를 Elasticsearch 게시글 검색에 도입하는 것을 정확하게 설명하며, 간결하고 구체적인 표현으로 팀원들이 커밋 이력을 스캔할 때 주요 변경 사항을 쉽게 이해할 수 있습니다.
Linked Issues Check ✅ Passed 연결된 이슈 #164의 목표인 "Elasticsearch 게시글 검색에 Redis 캐시 도입"과 "테스트 작성"이 모두 충족되었습니다. 코드 변경 사항에서 PostSearchCacheRepository 인터페이스 및 RedisPostSearchCacheRepository 구현체, PostSearchCacheProperties 설정, PostQueryService의 캐시 통합, 캐시 무효화를 위한 PostSearchCacheEventHandler, 그리고 PostSearchCacheEventHandlerTest 및 PostFinderTest의 캐시 관련 테스트가 포함되어 있습니다. 또한 벤치마크 시뮬레이션과 JMH 벤치마크 코드가 캐시 시나리오를 검증하는 데 기여합니다.
Out of Scope Changes Check ✅ Passed
Description Check ✅ Passed PR 설명은 저장소의 템플릿 구조를 따르고 있으며, 모든 주요 섹션이 작성되어 있습니다. 📌 Issue(관련 이슈: closed #164), 🧐 현재 상황, 🎯 목표, 🛠 작업 내용이 모두 포함되어 있고, 작업 항목도 체크 박스로 명확히 표시되어 있습니다. 다만 현재 상황과 목표 섹션이 동일한 내용으로 작성되어 있어 약간의 중복이 있지만, 필수 정보는 충분히 제공되고 있습니다.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat#164-Redis

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8523a3d and c7ecfd7.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (3)
.github/workflows/ci.yml (3)

35-43: ✅ Redis 서비스 구성이 올바르게 설정됨

Redis 서비스가 일관된 패턴으로 적절히 추가되었습니다:

  • redis:7-alpine 이미지 선택으로 가벼운 구성 유지
  • 표준 포트 6379 노출
  • redis-cli ping 헬스 체크로 Redis 가용성 확인
  • 다른 서비스와 일관된 헬스 체크 설정 (10s interval, 5s timeout, 10 retries)

103-121: ✅ 서비스 준비 상태 확인 로직이 Redis 포함하도록 업데이트됨

준비 상태 확인 스크립트가 Redis를 포함하도록 올바르게 업데이트되었습니다:

  • Line 105: 로그 메시지에 Redis 추가
  • Line 109: Redis 준비 상태 확인 추가 (nc -z localhost 6379)
  • Line 111: 세 서비스(Elasticsearch, Kafka, Redis) 모두 준비될 때까지 대기

패턴이 일관되고 논리가 정확합니다.


123-134: 원본 리뷰 의견은 부정확합니다 - Redis는 이미 CI 워크플로우에서 올바르게 설정되어 있습니다.

CI 워크플로우를 검증한 결과, Redis 서비스가 이미 구성되어 있음을 확인했습니다:

  • 라인 35-42: Redis 서비스 컨테이너 정의 (redis:7-alpine)
  • 라인 109-111: 테스트 실행 전 Redis 준비 상태 확인 (redis_ready 체크)
  • 기본 연결: Spring Boot는 기본값으로 localhost:6379에 자동 연결되므로 명시적 환경 변수 불필요

Elasticsearch와 Kafka와 달리 Redis는 명시적 환경 변수가 필요하지 않습니다. Spring Boot의 자동 설정이 기본 포트에서 localhost 연결을 처리하며, 이미 CI 워크플로우의 서비스 컨테이너로 제공됩니다.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/main/java/dooya/see/application/post/required/PostSearchCacheRepository.java (1)

12-35: 캐시 무효화 전략 개선 제안

현재 evictAll() 메서드만 제공되어 전체 캐시를 삭제합니다. 특정 게시글 변경 시 관련된 검색 키워드 캐시만 선택적으로 무효화할 수 있는 메서드를 추가하면 성능이 개선될 수 있습니다.

다음과 같은 메서드 추가를 고려해보세요:

    /**
     * 검색 캐시 전체를 삭제합니다.
     */
    void evictAll();
+
+    /**
+     * 특정 키워드의 캐시를 삭제합니다.
+     *
+     * @param keyword 삭제할 검색 키워드
+     */
+    void evict(String keyword);

참고: 현재는 전체 무효화로도 충분할 수 있지만, 트래픽이 증가하면 선택적 무효화가 유용할 것입니다.

src/main/java/dooya/see/adapter/integration/cache/config/PostSearchCacheProperties.java (1)

7-21: TTL 값 검증 추가 고려

현재 TTL 설정에 대한 검증이 없어 음수 또는 과도하게 큰 값이 설정될 수 있습니다. 운영 환경에서 잘못된 설정으로 인한 문제를 방지하기 위해 검증을 추가하는 것이 좋습니다.

다음과 같이 검증 로직을 추가할 수 있습니다:

+import jakarta.validation.constraints.Positive;
+
 @ConfigurationProperties(prefix = "see.cache.post-search")
 public class PostSearchCacheProperties {
     /**
      * 검색 결과 캐시 TTL.
      */
+    @Positive
     private Duration ttl = Duration.ofMinutes(3);

     public Duration getTtl() {
         return ttl;
     }

     public void setTtl(Duration ttl) {
+        if (ttl == null || ttl.isNegative() || ttl.isZero()) {
+            throw new IllegalArgumentException("TTL must be positive");
+        }
         this.ttl = ttl;
     }
 }
src/main/java/dooya/see/application/post/PostSearchCacheEventHandler.java (1)

59-66: 선택적 캐시 무효화를 고려해보세요.

현재 구현은 특정 게시글 변경 시 모든 검색 캐시를 무효화합니다(evictAll()). 이는 간단하지만, 변경된 게시글과 관련된 검색 결과만 선택적으로 무효화하면 캐시 효율성을 개선할 수 있습니다.

예를 들어, 게시글 제목/내용에 특정 키워드가 포함된 경우에만 해당 키워드의 캐시를 무효화하는 방식을 고려할 수 있습니다. 다만, 현재의 전체 무효화 방식도 구현이 단순하고 일관성을 보장하므로, 캐시 부하가 문제가 되지 않는다면 현재 방식을 유지해도 무방합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd54ee and 8523a3d.

📒 Files selected for processing (12)
  • README.md (1 hunks)
  • build.gradle.kts (1 hunks)
  • src/gatling/scala/dooya/see/search/PostSearchSimulation.scala (2 hunks)
  • src/jmh/java/dooya/see/benchmark/PostSearchBenchmark.java (3 hunks)
  • src/main/java/dooya/see/adapter/integration/cache/RedisPostSearchCacheRepository.java (1 hunks)
  • src/main/java/dooya/see/adapter/integration/cache/config/PostSearchCacheProperties.java (1 hunks)
  • src/main/java/dooya/see/adapter/integration/cache/config/RedisConfig.java (1 hunks)
  • src/main/java/dooya/see/application/post/PostQueryService.java (4 hunks)
  • src/main/java/dooya/see/application/post/PostSearchCacheEventHandler.java (1 hunks)
  • src/main/java/dooya/see/application/post/required/PostSearchCacheRepository.java (1 hunks)
  • src/test/java/dooya/see/application/post/PostSearchCacheEventHandlerTest.java (1 hunks)
  • src/test/java/dooya/see/application/post/provided/PostFinderTest.java (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-26T11:11:27.801Z
Learnt from: Do-oya
PR: see-projects/back#124
File: src/main/java/dooya/see/application/post/PostModifyService.java:19-21
Timestamp: 2025-08-26T11:11:27.801Z
Learning: PostModifyService에서 현재 EventListener를 사용하는 이유: 테스트 환경에서 RestrictedTransactionalEventListenerFactory 에러가 발생하여 TransactionalEventListener 적용이 지연됨. 현재는 애플리케이션 레이어에서 멱등성(isAlreadyLiked 체크)으로 안전성을 보장하고 있음.

Applied to files:

  • src/main/java/dooya/see/application/post/PostSearchCacheEventHandler.java
📚 Learning: 2025-05-25T09:48:50.258Z
Learnt from: Do-oya
PR: see-projects/back#53
File: src/test/java/dooya/see/post/application/PostQueryServiceTest.java:51-61
Timestamp: 2025-05-25T09:48:50.258Z
Learning: In PostQueryServiceTest, when testing failure cases where entities don't exist, explicit mocking of repository methods to return Optional.empty() is not necessary since Mockito's default behavior already handles this. The user prefers to keep tests simple by relying on Mockito's default behavior rather than over-mocking.

Applied to files:

  • src/test/java/dooya/see/application/post/provided/PostFinderTest.java
  • src/test/java/dooya/see/application/post/PostSearchCacheEventHandlerTest.java
  • src/main/java/dooya/see/application/post/PostQueryService.java
🧬 Code graph analysis (1)
src/main/java/dooya/see/adapter/integration/cache/RedisPostSearchCacheRepository.java (1)
src/main/java/dooya/see/adapter/integration/cache/key/PostCacheKey.java (1)
  • PostCacheKey (9-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: build-check
🔇 Additional comments (20)
build.gradle.kts (1)

86-88: LGTM: JMH JAR 파일 크기 제한 해제

JMH 벤치마크 JAR 생성 시 Zip64 형식을 활성화하여 대용량 파일 처리를 지원합니다. 벤치마크 시나리오 확장에 적절한 설정입니다.

src/gatling/scala/dooya/see/search/PostSearchSimulation.scala (2)

20-26: LGTM: 캐시 성능 테스트를 위한 Hot/Cold 키워드 분리

hotKeywordcoldKeyword를 구분하여 캐시 히트/미스 시나리오를 명확하게 테스트할 수 있습니다. nanoTime() 사용으로 고유한 cold 키워드를 보장하는 것도 적절합니다.


42-48: LGTM: 캐시 워밍 시나리오 추가

캐시를 미리 워밍하기 위한 별도의 HTTP 요청을 .silent 모드로 실행하여 결과 리포트에서 제외하는 것이 적절합니다.

src/jmh/java/dooya/see/benchmark/PostSearchBenchmark.java (3)

87-93: ColdSearchState의 캐시 무효화 시점 확인 필요

@Setup(Level.Invocation)으로 매 호출마다 캐시를 무효화하는 것은 cold search를 정확히 측정하기 위해 적절합니다. 다만 워밍업(warmup) 단계에서도 이 동작이 적용되므로, 워밍업 효과가 제한적일 수 있습니다.

현재 구성이 의도한 대로 동작하는지 확인하세요:

  1. 워밍업 단계: 캐시가 반복적으로 무효화되어 JVM 최적화 효과만 얻음
  2. 측정 단계: 매 측정마다 캐시 미스 상황을 정확히 측정

JMH 결과를 분석하여 cold search의 측정값이 예상 범위 내인지 확인하세요.


53-56: 캐시 워밍 전략 검토

setup에서 동일한 cacheHitQuery로 DB 조회와 ES 조회를 모두 수행하여 캐시를 워밍합니다. 이는 CachedSearchState의 캐시 히트 벤치마크에 적합하지만, ColdSearchState는 매 호출마다 캐시를 무효화하므로 이 워밍업의 영향을 받지 않습니다.


114-122: LGTM: 데이터베이스 검색 벤치마크 추가

ES 검색과 DB 검색의 성능을 비교할 수 있도록 databaseSearch 벤치마크를 추가한 것이 좋습니다. PostSearchRequest를 올바르게 구성하고 있습니다.

README.md (1)

30-30: LGTM: Redis 캐시 기능 문서화

Elasticsearch 검색 결과 캐싱 기능을 README에 명확히 문서화했습니다. TTL 3분 설정도 구현과 일치합니다.

src/main/java/dooya/see/adapter/integration/cache/config/RedisConfig.java (1)

3-3: LGTM: Configuration Properties 활성화

@EnableConfigurationProperties를 사용하여 PostSearchCacheProperties를 Spring Bean으로 등록하는 것이 적절합니다.

Also applies to: 11-11

src/test/java/dooya/see/application/post/PostSearchCacheEventHandlerTest.java (1)

32-66: LGTM: 포괄적인 캐시 무효화 이벤트 테스트

모든 도메인 이벤트(생성, 업데이트, 발행, 숨김, 삭제)와 명시적 무효화 명령에 대한 테스트가 잘 작성되어 있습니다. Mock 설정도 최소화하여 Mockito의 기본 동작을 활용하고 있습니다.

Based on learnings

src/main/java/dooya/see/application/post/PostQueryService.java (2)

77-78: 캐시 조회 로직이 깔끔합니다.

Optional 패턴과 orElseGet을 사용한 캐시 미스 처리가 적절합니다.


99-108: 캐시 저장 실패 처리가 적절합니다.

캐시 저장 실패 시 검색 흐름에 영향을 주지 않도록 경고 로그만 남기는 방식이 올바릅니다. 캐시는 성능 최적화를 위한 것이므로 실패해도 핵심 기능에 영향을 주지 않아야 합니다.

src/main/java/dooya/see/adapter/integration/cache/RedisPostSearchCacheRepository.java (5)

34-50: 역직렬화 실패 처리가 잘 되어 있습니다.

역직렬화 실패 시 손상된 캐시 엔트리를 삭제하는 방식이 적절합니다. 이를 통해 다음 요청 시 새로운 데이터로 캐시가 갱신됩니다.


52-68: TTL 처리 로직이 올바릅니다.

TTL이 null, 0, 또는 음수인 경우 TTL 없이 저장하는 로직이 적절합니다.


79-89: 키워드 정규화가 적절합니다.

Locale.ROOT를 사용한 소문자 변환은 로케일별 대소문자 변환 문제(예: 터키어의 'I' 문제)를 방지합니다. "Spring"과 "spring"이 동일한 캐시 키를 생성하도록 하는 것도 올바른 접근입니다.


91-102: 캐시용 레코드 구조가 효율적입니다.

CachedPage 레코드가 필요한 최소한의 데이터(content, totalElements)만 저장하여 직렬화 크기를 최적화했습니다.


70-77: 검증 완료: 키 패턴 일관성 확인됨

SEARCH_KEY_PATTERNPostCacheKey.search()로 생성된 키와 완벽하게 일치합니다.

  • PostCacheKey.search()post:search:<hash>:<page>:<size> 형식으로 키 생성 (src/main/java/dooya/see/adapter/integration/cache/key/PostCacheKey.java:28-30)
  • SEARCH_KEY_PATTERN = "post:search:*"는 이 형식의 모든 키를 정확하게 매칭
  • evictAll() 메서드의 패턴 매칭이 올바르게 동작함
src/test/java/dooya/see/application/post/provided/PostFinderTest.java (2)

47-47: 테스트 격리가 잘 되어 있습니다.

각 테스트 전에 캐시를 초기화하여 테스트 간 상태 공유를 방지합니다.


356-379: 캐시 동작을 잘 검증하는 테스트입니다.

Elasticsearch 데이터를 삭제한 후에도 캐시된 결과가 반환되는지 확인하여 캐시가 제대로 작동하는지 검증합니다.

src/main/java/dooya/see/application/post/PostSearchCacheEventHandler.java (2)

23-51: 이벤트 리스너 설정이 적절합니다.

AFTER_COMMIT 페이즈를 사용하여 트랜잭션 성공 후에만 캐시를 무효화하고, @Async를 통해 비동기로 처리하여 메인 트랜잭션을 차단하지 않습니다.


59-66: 캐시 무효화 실패 처리가 안전합니다.

캐시 무효화 실패 시 예외를 다시 던지지 않아 이벤트 처리 흐름이 중단되지 않습니다. 캐시는 부가 기능이므로 실패해도 핵심 비즈니스 로직에 영향을 주지 않아야 합니다.

- CI 환경에서 Redis 컨테이너 추가로 Redis 연동 테스트 지원
- Redis 초기화 및 상태 확인을 위한 health check 설정 포함
- Elasticsearch, Kafka 대기 로직에 Redis 상태 검사 로직 통합
- 검색 캐시 및 Redis 관련 기능의 CI 테스트 커버리지 확장
@Do-oya Do-oya merged commit 305f83d into dev Oct 30, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 ✅ Test test 관련(storybook, jest...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Elasticsearch 게시글 검색에 Redis 캐시 도입

2 participants