Skip to content

Conversation

@hykim02
Copy link
Collaborator

@hykim02 hykim02 commented Apr 17, 2025

[식단 조회 캐싱 적용]

  • 식단 메뉴
  • campusId
  • cafeteriaURL
  • cafeteriaId
  • campusName

쿼리문 중복 요청 원인 찾아 제거함

Summary by CodeRabbit

  • New Features
    • Improved caching for cafeteria, campus, and diet-related data, with longer cache durations and more granular cache keys for enhanced performance.
    • Added new caching for cafeteria image URLs.
  • Bug Fixes
    • Removed unused dependencies and imports to streamline the application.
  • Refactor
    • Simplified and optimized diet menu retrieval logic to reduce redundant data fetching.
    • Updated cache key usage for consistency and efficiency.
  • Chores
    • Enabled logging capabilities across multiple services for better monitoring and troubleshooting.
    • Removed deprecated configuration for HTTP request handling.

@coderabbitai
Copy link

coderabbitai bot commented Apr 17, 2025

Walkthrough

This change set refactors and enhances the caching strategy across several service classes in the application. It updates the TTLs for multiple Redis caches, introduces new cache entries, and enables or modifies @Cacheable annotations for various service methods. The caching logic for diet lists is moved from annotation-based to a manual RedisTemplate approach with dynamic TTL calculation. Several classes are now annotated with Lombok’s @Slf4j for logging support. Additionally, a redundant RestTemplate configuration class is removed, and some unused imports and dependencies are cleaned up.

Changes

File(s) Change Summary
src/main/java/com/example/Jinus/config/RedisCacheManager.java Updated cache TTLs: increased several caches to 30 days, disabled "dietList" cache, added "cafeteriaUrl" cache, and maintained serializers and null value caching settings.
src/main/java/com/example/Jinus/config/RestTemplateConfig.java Deleted the configuration class providing a custom RestTemplate bean with UTF-8 support and buffering.
src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java Removed unused ObjectMapper dependency and its injection.
src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java Refactored getDietList to use manual Redis caching with dynamic TTL; enabled and adjusted @Cacheable for getCafeteriaList; added logging support.
src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaQueryServiceV2.java Enabled and updated @Cacheable on getCafeteriaId; added @Cacheable for getImgUrl; added logging support.
src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java Added @Cacheable for getUserCampusName and getCampusId; added logging support.
src/main/java/com/example/Jinus/service/v2/cafeteria/DietParameterServiceV2.java Added @Slf4j logging annotation.
src/main/java/com/example/Jinus/service/v2/cafeteria/DietQueryServiceV2.java Simplified diet existence check; consolidated diet list retrieval; changed method signatures; added logging support.
src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java Removed unused imports; added logging support.
src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java Added @Slf4j logging annotation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant DietControllerV2
    participant CacheServiceV2
    participant Redis
    participant Database

    Client->>DietControllerV2: handleRequest(params)
    DietControllerV2->>CacheServiceV2: getDietList(params, cafeteriaId)
    CacheServiceV2->>Redis: GET dietList cache by key
    alt Cache hit
        Redis-->>CacheServiceV2: Return cached diet list
        CacheServiceV2-->>DietControllerV2: Return diet list
    else Cache miss
        CacheServiceV2->>Database: Query diet list
        Database-->>CacheServiceV2: Return diet list
        CacheServiceV2->>Redis: SET diet list with TTL (until next midnight)
        CacheServiceV2-->>DietControllerV2: Return diet list
    end
    DietControllerV2-->>Client: Return response
Loading

Possibly related PRs

  • GNU-connect/Server-JavaSpring#34: Re-enables and modifies caching annotations on getCafeteriaId in CafeteriaQueryServiceV2, directly related to this PR's changes to caching.
  • GNU-connect/Server-JavaSpring#33: Updates cache TTLs and cache configurations in RedisCacheManager, overlapping with this PR's cache strategy changes.

Poem

In the warren of code, the caches now gleam,
TTLs extended, a developer’s dream.
Diet lists cached ‘til midnight anew,
Logging with Lombok—so much to do!
Old beans are retired, new keys take their place,
This bunny hops forward, with a smile on its face.
🥕✨

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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.

@hykim02 hykim02 merged commit 5288921 into GNU-connect:main Apr 17, 2025
1 of 2 checks passed
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: 2

🧹 Nitpick comments (6)
src/main/java/com/example/Jinus/service/v2/cafeteria/DietParameterServiceV2.java (1)

18-18: Leverage or remove the injected log
You’ve added @Slf4j to enable logging, but there are currently no log statements in this class. Consider adding log entries (e.g., entering/exiting methods, key parameter values, or error conditions) to improve traceability, or remove the annotation if logging isn’t needed here.

src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java (1)

16-16: Enable SLF4J logging
Annotating the class with @Slf4j is appropriate. To fully leverage this change, consider inserting log.debug() or log.info() statements in key methods (e.g., upon entry to requestHandler, cache misses/hits, error branches) for better observability.

src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java (1)

15-15: Enable structured logging with @Slf4j.
The @Slf4j annotation correctly injects a log instance for this service. Consider adding meaningful log statements (e.g., cache‐hit vs. cache‐miss events, entry/exit of critical methods) to leverage this enhancement and improve observability.

src/main/java/com/example/Jinus/config/RedisCacheManager.java (1)

49-50: Fix duplicate comment numbering

There are two sections labeled as "3." - one for campusName and another for cafeteriaId. Please correct the numbering in the comments.

-        // 3. 식당 id 캐시 (불변 데이터, 30일 유지)
+        // 4. 식당 id 캐시 (불변 데이터, 30일 유지)
-        // 4. 캠퍼스 id 캐시 (불변 데이터, 30일 유지)
+        // 5. 캠퍼스 id 캐시 (불변 데이터, 30일 유지)
-        // 5. 식당 url 캐시 (불변 데이터, 30일 유지)
+        // 6. 식당 url 캐시 (불변 데이터, 30일 유지)

Also applies to: 57-58

src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java (2)

31-33: Add explicit type safety to the Redis read to prevent ClassCastException

(List<DietDto>) redisTemplate.opsForValue().get(key) relies on unchecked casting.
Configure the template with a Jackson2JsonRedisSerializer<List<DietDto>> (or your preferred serializer) and parameterise it:

private final RedisTemplate<String, List<DietDto>> redisTemplate;
...
List<DietDto> cached = redisTemplate.opsForValue().get(key);

This eliminates raw‑type warnings and guards against accidental type mismatches if another component writes to the same key.


21-22: @Slf4j added but never used

Since logging was introduced, consider logging cache hits/misses inside getDietList and getCafeteriaList to aid future debugging and performance analysis.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7c72f4 and 931b37c.

📒 Files selected for processing (10)
  • src/main/java/com/example/Jinus/config/RedisCacheManager.java (2 hunks)
  • src/main/java/com/example/Jinus/config/RestTemplateConfig.java (0 hunks)
  • src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java (0 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java (1 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaQueryServiceV2.java (1 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java (2 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/DietParameterServiceV2.java (2 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/DietQueryServiceV2.java (2 hunks)
  • src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java (1 hunks)
  • src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java (2 hunks)
💤 Files with no reviewable changes (2)
  • src/main/java/com/example/Jinus/config/RestTemplateConfig.java
  • src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java
🔇 Additional comments (16)
src/main/java/com/example/Jinus/service/v2/cafeteria/DietParameterServiceV2.java (1)

8-8: Lombok SLF4J import added correctly
The import for lombok.extern.slf4j.Slf4j is in place. Ensure that Lombok annotation processing is enabled in your build (e.g., maven-compiler-plugin or IDE configuration) so the log field is generated without issues.

src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java (1)

7-7: Approved: Import for logging support
The addition of lombok.extern.slf4j.Slf4j is correct and prepares the class for structured logging.

src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java (1)

5-5: Approve addition of SLF4J import.
Importing lombok.extern.slf4j.Slf4j is necessary to activate the @Slf4j annotation and aligns with other service classes.

src/main/java/com/example/Jinus/config/RedisCacheManager.java (4)

24-30: Good update to cafeteria list cache TTL

Extending the TTL to 30 days for immutable cafeteria list data is appropriate and helps reduce unnecessary database queries.


41-48: Consistent caching strategy for immutable data

Good approach applying 30-day TTL consistently across all immutable data caches (campusName, cafeteriaId, campusId).

Also applies to: 49-63


65-71: Good addition of cafeteriaUrl cache

Adding the cafeteriaUrl cache with a 30-day TTL for immutable data is consistent with the overall caching strategy.


34-39:

Details

✅ Verification successful

Confirm if dietList cache removal is intentional

The dietList cache configuration is now commented out. This suggests that the caching strategy for diet data has changed, likely to a manual implementation using RedisTemplate with dynamic TTL as mentioned in the summary.

Please verify that the corresponding diet data caching is now being handled manually elsewhere in the code (likely in CacheServiceV2 with RedisTemplate).


🏁 Script executed:

#!/bin/bash
# Check for RedisTemplate usage in CacheServiceV2
rg -A 10 "RedisTemplate|getDietList" src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java

Length of output: 1063


dietList cache is now managed manually in CacheServiceV2

The commented‑out dietList entry in RedisCacheManager is intentional. Caching is now handled in CacheServiceV2’s getDietList method using RedisTemplate with a dynamic TTL:

• File: src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java
– Method: getDietList(HandleRequestDto, int)
– Uses redisConfig.redisTemplate().opsForValue().get(key) and .set(key, result, Duration.ofSeconds(ttlSeconds)) where ttlSeconds is calculated until next midnight.

src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaQueryServiceV2.java (3)

5-11: Good addition of logging support

Adding the @slf4j annotation enables proper logging capabilities in this service class.


15-22: Good implementation of caching for cafeteriaId lookups

The @Cacheable annotation is properly configured with:

  • Appropriate cache name
  • Well-formatted composite key using both parameters
  • Condition to prevent caching of "not found" results (-1)
  • Explicit cache manager reference

This will effectively reduce database queries for these lookups.


24-30: Good implementation of caching for cafeteria image URLs

Adding caching for the getImgUrl method is beneficial as image URLs are unlikely to change frequently. The cache configuration is properly set up with the appropriate cache name, key, and cache manager.

src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java (3)

6-14: Good addition of logging and cache imports

Adding the @slf4j annotation and importing the necessary caching annotations is appropriate for the changes in this class.


18-25: Good implementation of caching for campus name lookups

The @Cacheable annotation on getUserCampusName is properly configured with:

  • Appropriate cache name
  • Simple key using the campusId parameter
  • Explicit cache manager reference

This will effectively reduce database queries for campus name lookups.


32-39: Good implementation of caching for campus ID lookups

The @Cacheable annotation on getCampusId is properly configured with:

  • Appropriate cache name
  • Simple key using the campusName parameter
  • Explicit cache manager reference

This will effectively reduce database queries for campus ID lookups.

src/main/java/com/example/Jinus/service/v2/cafeteria/DietQueryServiceV2.java (3)

7-19: Good addition of logging support

Adding the @slf4j annotation enables proper logging capabilities in this service class.


26-36: Excellent optimization to eliminate redundant data fetching

The refactored code now retrieves the diet list only once from cacheServiceV2 and checks if it's empty, rather than querying twice (once to check existence, once to retrieve data). This is a significant improvement that reduces duplicate queries.


40-51: Good refactoring of getDiets method

Changing the getDiets method to accept a pre-fetched list of DietDto objects instead of fetching them internally eliminates redundant data retrieval and makes the method more reusable. This change works well with the optimized getDietResponse method.

Comment on lines +31 to +39
List<DietDto> cached = (List<DietDto>) redisConfig.redisTemplate().opsForValue().get(key);
if (cached != null) return cached;

List<DietDto> result = dietRepositoryV2.findDietList(parameters.getDietDate(), parameters.getPeriod(), cafeteriaId);

if (result != null && !result.isEmpty()) {
long ttlSeconds = calculateTtlUntilNextMidnight(parameters.getDietDate());
redisConfig.redisTemplate().opsForValue().set(key, result, Duration.ofSeconds(ttlSeconds));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Skip the SET operation when TTL ≤ 0 to avoid creating instantly‑expired keys

If calculateTtlUntilNextMidnight returns 0, the current code still executes

redisTemplate.opsForValue().set(key, result, Duration.ofSeconds(0));

With Redis this translates to a SETEX key 0, which immediately expires the key and produces unnecessary network traffic.
Guard the call with a positive‑TTL check instead:

long ttlSeconds = calculateTtlUntilNextMidnight(parameters.getDietDate());
-if (ttlSeconds > 0) {
-    redisTemplate.opsForValue().set(key, result, Duration.ofSeconds(ttlSeconds));
-}
+if (ttlSeconds > 0) {
+    redisTemplate.opsForValue().set(key, result, Duration.ofSeconds(ttlSeconds));
+} else {
+    log.debug("Diet cache not written because TTL is non‑positive for key={}", key);
+}

Comment on lines +26 to +33
private final RedisConfig redisConfig;

// @Cacheable(
// value = "dietList",
// key = "#parameters?.dietDate?.toString() + '::' + #parameters?.period + '::' + #cafeteriaId",
// unless = "#result == null || #result.isEmpty()",
// cacheManager = "contentCacheManager"
// )
// 식단 데이터 가져오기
public List<DietDto> getDietList(HandleRequestDto parameters, int cafeteriaId) {
// 오늘, 내일 문자열로 날짜 설정하기
Date dietDate = parameters.getDietDate();
// 식단 데이터 반환
return dietRepositoryV2.findDietList(dietDate, parameters.getPeriod(), cafeteriaId);
String key = parameters.getDietDate() + "::" + parameters.getPeriod() + "::" + cafeteriaId;

List<DietDto> cached = (List<DietDto>) redisConfig.redisTemplate().opsForValue().get(key);
if (cached != null) return cached;

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prefer constructor‑injected RedisTemplate over calling the RedisConfig factory on every invocation

redisConfig.redisTemplate() is executed on every call to getDietList.
Even though the factory method is likely annotated with @Bean, Spring still has to look the bean up each time, and the indirection hides the real dependency of this service (the template, not the config).

Injecting the template directly makes dependencies explicit, avoids the per‑call lookup, and removes the need to expose the redisTemplate() factory method altogether.

-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.redis.core.RedisTemplate;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
 ...
-    private final RedisConfig redisConfig;
+    private final RedisTemplate<String, Object> redisTemplate;

Update the two call‑sites (get / set) to use redisTemplate instead of redisConfig.redisTemplate().
This keeps the service focused and eases unit testing (you can now pass a mocked template).

Committable suggestion skipped: line range outside the PR's diff.

@sentry
Copy link

sentry bot commented Apr 17, 2025

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

  • ‼️ QueryTimeoutException: Redis command timed out POST /api/spring/v2/dish View Issue

Did you find this useful? React with a 👍 or 👎

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