Skip to content

[Refactor] Redis 추가#86

Merged
chaeyuuu merged 7 commits intomainfrom
refactor/add-redis
Sep 4, 2025
Merged

[Refactor] Redis 추가#86
chaeyuuu merged 7 commits intomainfrom
refactor/add-redis

Conversation

@chaeyuuu
Copy link
Copy Markdown
Contributor

@chaeyuuu chaeyuuu commented Sep 4, 2025

💻 Related Issue

closed #85


🚀 Work Description

  • 뉴스 api에 redis 추가

Summary by CodeRabbit

  • New Features
    • 뉴스 목록에 Redis 기반 캐시를 도입해 조회 성능과 응답 일관성을 개선했습니다.
    • 뉴스 목록 조회 결과를 캐시하며 수동/자동 수집 후 관련 캐시가 자동으로 갱신되도록 처리했습니다.
  • Chores
    • Redis 지원과 JSON 직렬화를 위한 런타임 의존성을 추가했습니다.
    • 캐시 인프라와 기본/뉴스 전용 TTL 정책(기본 30분, 뉴스 24시간)을 설정했습니다.
  • Style
    • 응답 DTO에 기본 생성자를 추가해 직렬화/역직렬화 호환성을 개선했습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 4, 2025

Walkthrough

Redis 캐시를 도입해 뉴스 목록을 캐싱하고 관련 캐시를 무효화하도록 변경했다. Gradle에 Spring Boot/Redis/Jackson 의존성을 추가했고 Redis 설정 클래스를 신설했으며 서비스에 @Cacheable, 스케줄러/관리자 API에 @CacheEvict를 적용하고 DTO들에 무인자 생성자를 추가했다.

Changes

Cohort / File(s) Summary
Build config
build.gradle
의존성 추가: org.springframework.boot:spring-boot-starter, org.springframework.boot:spring-boot-starter-data-redis, com.fasterxml.jackson.core:jackson-databind
Caching 적용
src/main/java/com/blockguard/server/domain/news/application/NewsService.java, src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java, src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java
NewsService.getNewsList(...)@Cacheable(value = "news:list:v2", key = ...) 추가. 스케줄러 및 AdminApi.crawlNewsManually()@CacheEvict(value = "news:list:v2", allEntries = true) 추가 (기존 시그니처 유지)
Redis 구성
src/main/java/com/blockguard/server/global/config/RedisConfig.java
신규 구성 클래스 추가: @Configuration, @EnableCaching, RedisConnectionFactory(Lettuce) 및 CacheManager(RedisCacheManager) 빈 등록. 기본 TTL 30분, news:list:v2는 24시간 TTL, String 키/JSON 값 직렬화
DTO 무인자 생성자
src/main/java/com/blockguard/server/domain/news/dto/response/NewsArticleResponse.java, .../NewsPageResponse.java, .../PageableInfo.java
Lombok @NoArgsConstructor 추가로 무인자 생성자 생성(기존 필드/동작 불변)

Sequence Diagram(s)

sequenceDiagram
    participant C as 클라이언트
    participant S as NewsService
    participant API as AdminApi/스케줄러
    participant Cache as Redis Cache
    participant DB as Repository/DB

    rect rgb(234,248,255)
    note over C,S: 뉴스 목록 조회 (캐시 우선)
    C->>S: getNewsList(page,size,sort,category)
    S->>Cache: 조회 (news:list:v2:key)
    alt 캐시 적중
        Cache-->>S: 캐시된 결과
        S-->>C: 결과 반환
    else 캐시 미스
        S->>DB: 데이터 조회
        DB-->>S: 결과
        S->>Cache: 저장 (news:list:v2:key)
        S-->>C: 결과 반환
    end
    end

    rect rgb(244,240,255)
    note over C,API: 수동 크롤/스케줄러 (캐시 무효화)
    C->>API: crawlNewsManually()/crawlingForAdmin()/saveNewsArticles()
    API->>Cache: @CacheEvict(allEntries=true) news:list:v2
    API-->>C: 완료 응답
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • [Feat] 뉴스 API #44 — 동일 영역(뉴스 캐싱/스케줄러/Redis 설정/DTO 생성자) 변경으로 강한 관련성 있음

Suggested reviewers

  • yeonju73

Poem

밤밭 달빛 아래 깡충 뛴 토끼예요 🐇
레디스에 뉴스 포근히 넣어두고
조회하면 폴짝—캐시에서 꺼내오죠
크롤하면 휙—비우고 다시 채워요
깡충, 변경 축하해요! ✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c3a51d8 and 59ad3d5.

📒 Files selected for processing (1)
  • src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/add-redis

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsArticleResponse.java (2)

24-33: 상대시간 문자열을 DTO에 고정 저장하면 캐시 시점이 굳어져 ‘시간 경과’ 표시가 영구히 stale 됩니다

현재 서비스 레벨에서 DTO 자체를 캐싱하고 TTL이 길면(요약에 따르면 24h) “x분 전/어제”가 실제 시간 경과와 불일치합니다. 해결책:

  • 캐시에는 절대시간(ISO 문자열 혹은 epoch)을 저장하고, 상대시간 포맷은 응답 직전(컨트롤러) 혹은 클라이언트에서 계산.
  • 또는 캐시 키에 시간 버킷(예: 10분) 포함 혹은 TTL을 수분 단위로 단축.

API 계약을 유지하면서 최소 변경으로 가려면 캐시 키에 시간 버킷을 넣는 방식을 추천합니다(서비스 코멘트 참조). 계약 변경이 가능하면 아래처럼 절대시간을 내려주세요.

-    private String publishedAt;
+    // 절대시간 (예: ISO-8601). 상대시간은 클라이언트에서 계산 권장
+    private String publishedAt;
...
-                .publishedAt(formatTime(newsArticle.getPublishedAt()))
+                .publishedAt(newsArticle.getPublishedAt().toString())

36-47: 미래 시각 입력 시 음수 지속시간 처리 버그

크롤러/서버 시계 불일치 등으로 publishedAt이 현재보다 미래면 “-5분 전” 같은 잘못된 문자열이 생성됩니다. 음수인 경우를 처리해 주세요.

-    private static String formatTime(LocalDateTime time) {
-        Duration duration = Duration.between(time, LocalDateTime.now());
+    private static String formatTime(LocalDateTime time) {
+        Duration duration = Duration.between(time, LocalDateTime.now());
+        if (duration.isNegative() || duration.isZero()) {
+            return "방금 전";
+        }
src/main/java/com/blockguard/server/domain/news/application/NewsService.java (1)

30-35: 검증 순서 오류로 PageRequest.of(...)에서 IllegalArgumentException이 먼저 발생할 수 있음

page/size 유효성 검증을 PageRequest 생성 이전으로 이동하세요. 현재는 page=0/size<1일 때 커스텀 예외 대신 프레임워크 예외가 먼저 던져집니다.

-        Pageable pageable = PageRequest.of(page - 1, size, getSort(sort));
-        Page<NewsArticle> newsPage;
-
-        if (page < 1 || size < 1) {
+        if (page < 1 || size < 1) {
             throw new BusinessExceptionHandler(ErrorCode.MUST_BE_POSITIVE_NUMBER);
         }
+        Pageable pageable = PageRequest.of(page - 1, size, getSort(sort));
+        Page<NewsArticle> newsPage;
build.gradle (1)

3-4: MySQL 커넥터 중복 선언 정리 필요

  • org.springframework.boot(3.5.3) 및 io.spring.dependency-management(1.1.7) 플러그인이 build.gradle에 정상 선언되어 있습니다.
  • implementation 'mysql:mysql-connector-java:8.0.29' 와 runtimeOnly 'com.mysql:mysql-connector-j' 두 개의 MySQL 커넥터가 중복 선언되어 있어 BOM 기반 관리나 런타임 의존성 충돌 우려가 있습니다. 하나로 통일하거나 그룹ID/버전을 일관되게 지정해 주세요.
🧹 Nitpick comments (7)
src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (1)

12-17: 캐시 스키마 변화 대비 내구성 강화 제안

향후 필드 추가/변경 시 역직렬화 오류를 줄이기 위해 아래와 같이 알 수 없는 필드를 무시하도록 하는 것을 고려해 주세요.

+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

-@Builder
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class PageableInfo {
src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (1)

14-18: 캐시 포맷 변경 내성 확보 제안

앞으로의 필드 증감에 대비해 알 수 없는 필드를 무시하도록 설정을 권장합니다.

+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 ...
-@NoArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class NewsPageResponse {
build.gradle (1)

34-36: 불필요/중복 의존성 정리 제안

  • spring-boot-starter는 개별 스타터(web/jpa/security 등)로 이미 커버되어 중복입니다.
  • jackson-databind는 web 스타터를 통해 관리되므로 명시 추가는 보통 불필요합니다(특별 버전 고정 필요 없으면 제거 권장).
-    implementation 'org.springframework.boot:spring-boot-starter'
     implementation 'org.springframework.boot:spring-boot-starter-data-redis'
-    implementation 'com.fasterxml.jackson.core:jackson-databind'
+    // Redis Value 직렬화에 Jackson을 사용할 때는 web 스타터의 Jackson으로 충분한 경우가 많습니다.
+    // 별도 버전 고정 필요 시에만 추가하세요.
src/main/java/com/blockguard/server/global/config/RedisConfig.java (4)

11-11: 불필요한 import 제거

위 빈 제거 후 LettuceConnectionFactory import가 사용되지 않습니다.

-import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

36-39: null 캐싱 방지 및 키 프리픽스 추가 권장

null 결과가 캐시에 저장되면 장애 시 복구 지연이 길어질 수 있습니다. 또한 키 프리픽스로 환경/서비스를 구분해 충돌을 줄이는 것이 좋습니다.

-        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
-                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
-                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
-                .entryTtl(Duration.ofMinutes(30));
+        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
+                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
+                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
+                .disableCachingNullValues()
+                .computePrefixWith(cacheName -> "bg:" + cacheName + "::")
+                .entryTtl(Duration.ofMinutes(30));

41-43: 24h TTL은 수동/배치 크롤 직후 최신 데이터 노출을 지연시킬 수 있습니다

현재 무효화가 컨트롤러 측(비동기 호출)에서 이루어져 크롤 완료 시점과 어긋날 여지가 있습니다. 스케줄러/크롤러 완료 시점에 무효화가 이뤄지는지 확인해 주세요. 필요 시 TTL을 단축(예: 1–3h)하거나 완료 후 무효화로 전환을 권장합니다.


45-50: 트랜잭션 인식 캐시 활성화 검토

DB 트랜잭션 롤백 시 캐시와 일관성 보장을 강화하려면 트랜잭션 인식을 켜는 것이 좋습니다.

                 .withInitialCacheConfigurations(cacheConfigs)
+                .transactionAware()
                 .build();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 635fe3f and 25c110c.

📒 Files selected for processing (7)
  • build.gradle (1 hunks)
  • src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java (2 hunks)
  • src/main/java/com/blockguard/server/domain/news/application/NewsService.java (2 hunks)
  • src/main/java/com/blockguard/server/domain/news/dto/response/NewsArticleResponse.java (1 hunks)
  • src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (1 hunks)
  • src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (1 hunks)
  • src/main/java/com/blockguard/server/global/config/RedisConfig.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (2)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (1)
  • Getter (10-18)
src/main/java/com/blockguard/server/domain/news/api/NewsApi.java (1)
  • RestController (17-44)
src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java (2)
src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java (4)
  • Async (43-47)
  • Async (38-41)
  • Component (14-62)
  • crawlAll (49-61)
src/main/java/com/blockguard/server/infra/crawler/DaumNewsCrawler.java (1)
  • Service (25-148)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsArticleResponse.java (3)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (1)
  • Getter (10-18)
src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (1)
  • Getter (8-17)
src/main/java/com/blockguard/server/domain/news/domain/NewsArticle.java (1)
  • Entity (10-43)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (2)
src/main/java/com/blockguard/server/domain/news/dto/response/NewsArticleResponse.java (1)
  • Getter (12-49)
src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (1)
  • Getter (8-17)
src/main/java/com/blockguard/server/domain/news/application/NewsService.java (2)
src/main/java/com/blockguard/server/domain/news/dao/NewsRepository.java (1)
  • NewsRepository (9-13)
src/main/java/com/blockguard/server/domain/news/api/NewsApi.java (3)
  • RestController (17-44)
  • GetMapping (36-42)
  • GetMapping (24-34)
🔇 Additional comments (3)
src/main/java/com/blockguard/server/domain/news/dto/response/PageableInfo.java (1)

6-11: DTO에 무인자 생성자 추가, 캐시/직렬화 호환성 향상 LGTM

Redis/Jackson 직렬화·역직렬화 시 문제 줄여주는 변경입니다.

src/main/java/com/blockguard/server/domain/news/dto/response/NewsPageResponse.java (1)

6-14: 무인자 생성자 추가 LGTM

Jackson/캐시 역직렬화 시 호환성에 도움 됩니다.

src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java (1)

16-16: 필요한 import 추가 OK

@CacheEvict 도입에 따른 import 추가는 적절합니다.

Comment thread build.gradle Outdated

@PostMapping("/crawl")
@Operation(summary = "뉴스 크롤링")
@CacheEvict(value = "news:list:v2", allEntries = true)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

비동기 크롤과 컨트롤러의 @CacheEvict 조합으로 stale 캐시가 24시간 잠길 수 있습니다

newsSaveScheduler.crawlingForAdmin()@Async라 이 컨트롤러 메서드는 즉시 종료되며, 캐시 비우기(기본 afterInvocation)는 크롤 완료 전 수행됩니다. 이후 클라이언트가 곧바로 조회하면 “이전 데이터”로 캐시가 다시 채워지고(24h TTL) 크롤 완료 후에도 최신 데이터가 노출되지 않습니다.

권장 수정(중 택1):

  • 옵션 A(권장): 컨트롤러의 @CacheEvict 제거 → 스케줄러 공개 메서드(예: crawlingForAdmin, saveNewsArticles)에 @CacheEvict(value = "news:list:v2", allEntries = true)를 붙이고 두 메서드의 @Async를 제거(스케줄러는 별도 스레드에서 실행되므로 불필요). 크롤 완료 후 무효화 보장.
  • 옵션 B: 이벤트/리스너로 전환 — 크롤 종료 시 ApplicationEvent 발행, 별도 리스너에서 @CacheEvict(allEntries = true) 실행.

이 파일에서의 1차 수정 diff(옵션 A 전제):

-    @CacheEvict(value = "news:list:v2", allEntries = true)

스케줄러 수정 예시(다른 파일):

// NewsSaveScheduler.java
@CacheEvict(value = "news:list:v2", allEntries = true)
public void crawlingForAdmin() {
    crawlAll(); // @Async 제거
}

@CacheEvict(value = "news:list:v2", allEntries = true)
public void saveNewsArticles() {
    crawlAll(); // @Async 제거 (@Scheduled는 그대로 사용)
}
🤖 Prompt for AI Agents
In src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java around
line 56, the controller-level @CacheEvict is clearing the cache immediately
while newsSaveScheduler.crawlingForAdmin() runs asynchronously, allowing the
cache to be repopulated with stale data before the crawl finishes; remove the
@CacheEvict from this controller method and instead annotate the scheduler's
public methods (e.g., crawlingForAdmin and saveNewsArticles) with
@CacheEvict(value = "news:list:v2", allEntries = true) and remove @Async from
those scheduler methods (or alternatively publish an ApplicationEvent from the
scheduler and have a listener perform @CacheEvict) so cache eviction happens
after crawling completes.

Comment on lines +28 to 29
@Cacheable(value = "news:list:v2", key = "'list:' + #page + ':' + #size + ':' + #sort + ':' + #category")
public NewsPageResponse getNewsList(int page, int size, String sort, String category) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

상대시간 필드가 포함된 DTO를 장시간 캐시하면 UI가 stale 됩니다 — 시간 버킷 포함 또는 TTL 단축 권장

현재 DTO(NewsArticleResponse.publishedAt)가 “x분 전” 식으로 포맷된 문자열이라 서비스 레벨 캐시(요약상 24h)와 충돌합니다. 두 가지 경로 중 하나를 선택하세요.

  • 빠른 적용: 캐시 키에 10분 버킷을 포함해 상대시간이 주기적으로 갱신되도록 함.
  • 근본 해결: 캐시는 엔티티/절대시간만 저장하고 DTO 변환은 캐시 hit 이후에 수행(또는 상대시간은 클라이언트 계산).

빠른 적용용 키 변경 예:

-    @Cacheable(value = "news:list:v2", key = "'list:' + #page + ':' + #size + ':' + #sort + ':' + #category")
+    // 10분 단위 버킷 추가로 상대시간 표시 stale 완화
+    @Cacheable(
+        value = "news:list:v2",
+        key = "'list:' + #page + ':' + #size + ':' + #sort + ':' + #category + ':' + (T(java.time.Instant).now().getEpochSecond() / 600)"
+    )

추가로 빈 결과는 캐시하지 않도록 할 수 있습니다(선택):

-    @Cacheable( ... )
+    @Cacheable( ..., unless = "#result == null || #result.news == null || #result.news.isEmpty()" )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Cacheable(value = "news:list:v2", key = "'list:' + #page + ':' + #size + ':' + #sort + ':' + #category")
public NewsPageResponse getNewsList(int page, int size, String sort, String category) {
// 10분 단위 버킷 추가로 상대시간 표시 stale 완화
@Cacheable(
value = "news:list:v2",
key = "'list:' + #page + ':' + #size + ':' + #sort + ':' + #category + ':' + (T(java.time.Instant).now().getEpochSecond() / 600)"
)
public NewsPageResponse getNewsList(int page, int size, String sort, String category) {
// … existing implementation …
}

Comment on lines +23 to +33
@Value("${spring.data.redis.host}")
private String host;

@Value("${spring.data.redis.port}")
private int port;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

직접 정의한 RedisConnectionFactory가 비밀번호/DB/SSL/타임아웃을 무시합니다

Spring Boot의 자동 설정을 덮어써서 spring.data.redis.password, database, ssl, sentinel/cluster, timeout 등 프로퍼티가 적용되지 않습니다. 운영에서 인증/DB 분리 시 연결 실패·데이터 오염 위험이 큽니다. 자동 설정으로 제공되는 RedisConnectionFactory를 그대로 주입받도록 이 빈을 제거하세요.

적용 diff:

-    @Value("${spring.data.redis.host}")
-    private String host;
-
-    @Value("${spring.data.redis.port}")
-    private int port;
-
-    @Bean
-    public RedisConnectionFactory redisConnectionFactory() {
-        return new LettuceConnectionFactory(host, port);
-    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
🤖 Prompt for AI Agents
In src/main/java/com/blockguard/server/global/config/RedisConfig.java around
lines 23-33, the explicitly defined RedisConnectionFactory using only host/port
overrides Spring Boot auto-configuration and ignores properties like
spring.data.redis.password, database, ssl, sentinel/cluster and timeout; remove
the custom @Bean method (and the host/port @Value fields if they are only used
for this) so Spring Boot can provide the auto-configured RedisConnectionFactory,
or if you must customize, construct the LettuceConnectionFactory via Spring's
RedisProperties and LettuceClientConfiguration so all standard properties are
honored.

Copy link
Copy Markdown

@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 (2)
src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java (2)

50-54: 스케줄러 주석 해제 의도 확인 필요 · 비동기 + 완료 후 캐시 무효화 동일 패턴 적용 제안

운영에서 자동 크롤링이 필요하다면 프로퍼티 기반 크론으로 복원하고, 위와 동일하게 비동기 실행 후 종료 시 캐시를 비우는 패턴이 안전합니다.

-    @CacheEvict(value = "news:list:v2", allEntries = true)
-    // @Scheduled(cron = "0 0 4 * * *")
+    @Async
+    @Scheduled(cron = "${app.news.crawl.cron:0 0 4 * * *}")
     public void saveNewsArticles() {
         crawlAll();
+        evictNewsListCache();
     }

7-7: 프로그램 방식 무효화로 전환 시 불필요한 import 정리

위 제안대로 @CacheEvict를 제거하면 해당 import도 함께 정리해주세요.

-import org.springframework.cache.annotation.CacheEvict;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 25c110c and c3a51d8.

📒 Files selected for processing (2)
  • build.gradle (1 hunks)
  • src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • build.gradle
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java (2)
src/main/java/com/blockguard/server/domain/admin/api/AdminApi.java (1)
  • PostMapping (53-58)
src/main/java/com/blockguard/server/infra/crawler/DaumNewsCrawler.java (1)
  • Service (25-148)
🔇 Additional comments (1)
src/main/java/com/blockguard/server/domain/news/scheduler/NewsSaveScheduler.java (1)

41-48: 현재 구현은 의도된 동작이며 변경 불필요
crawlingForAdmin()@Async가 없으므로 @CacheEvict(afterInvocation=false)는 메서드 리턴(크롤링 완료) 시점에 캐시를 무효화합니다. 스케줄러 전용 메서드여서 HTTP 요청 처리와도 분리되어 있어 블로킹 이슈가 발생하지 않습니다. 제안된 비동기 재적용 및 프로그램 방식 캐시 클리어는 불필요합니다.

Likely an incorrect or invalid review comment.

@chaeyuuu chaeyuuu merged commit cbb2e96 into main Sep 4, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] Redis 추가

1 participant