diff --git a/server/src/main/java/com/onixbyte/ahsarahguide/config/CacheConfig.java b/server/src/main/java/com/onixbyte/ahsarahguide/config/CacheConfig.java index 1b43650..5fdb3c4 100644 --- a/server/src/main/java/com/onixbyte/ahsarahguide/config/CacheConfig.java +++ b/server/src/main/java/com/onixbyte/ahsarahguide/config/CacheConfig.java @@ -1,9 +1,11 @@ package com.onixbyte.ahsarahguide.config; import com.onixbyte.ahsarahguide.shared.JacksonRedisSerialiser; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -39,21 +41,24 @@ import java.time.Duration; public class CacheConfig { /** - * Creates a custom Redis cache manager with JSON serialisation support. + * Creates the application's primary cache manager, backed by Redis. *
- * This method configures a {@link RedisCacheManager} that uses string serialisation for cache - * keys and {@link GenericJackson2JsonRedisSerializer} for cache values. This setup ensures that - * complex objects can be stored and retrieved from Redis cache whilst maintaining readability - * and compatibility with JSON-based systems. + * This manager is marked {@link Primary}, so it is the one selected for any + * {@code @Cacheable} or {@code @CacheEvict} annotation that does not name a manager + * explicitly, as well as for any {@link CacheManager} that is injected by type. + *
+ * Cache entries are keyed using string serialisation and values are stored as JSON via + * {@link JacksonRedisSerialiser}. Every entry expires after two hours, making this manager + * suitable for data that is expensive to compute but not required to survive for long. * * @param connectionFactory the Redis connection factory used to establish connections - * @return a configured {@link RedisCacheManager} with custom serialisation settings + * @return a fully configured {@link CacheManager} with a two-hour default entry TTL + * @see #longTermCacheManager(RedisConnectionFactory) * @see RedisCacheManager - * @see GenericJackson2JsonRedisSerializer - * @see RedisSerializationContext */ + @Primary @Bean - public RedisCacheManager cacheManager( + public CacheManager defaultCacheManager( RedisConnectionFactory connectionFactory ) { var _keySerializer = RedisSerializer.string(); @@ -63,7 +68,40 @@ public class CacheConfig { .fromSerializer(_keySerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(JacksonRedisSerialiser.INSTANCE)) - .entryTtl(Duration.ofMinutes(90L)); + .entryTtl(Duration.ofHours(2L)); + + return RedisCacheManager.RedisCacheManagerBuilder + .fromConnectionFactory(connectionFactory) + .cacheDefaults(cacheConfiguration) + .build(); + } + + /** + * Creates a secondary cache manager for data that must be retained for longer. + *
+ * This manager is not {@link Primary}; it must be requested by name wherever it is needed, + * as in {@code @Cacheable(cacheManager = "longTermCacheManager")}. + *
+ * Serialisation is configured identically to {@link #defaultCacheManager}, but entries
+ * expire after one day rather than two hours.
+ *
+ * @param connectionFactory the Redis connection factory used to establish connections
+ * @return a fully configured {@link CacheManager} with a one-day default entry TTL
+ * @see #defaultCacheManager(RedisConnectionFactory)
+ * @see RedisCacheManager
+ */
+ @Bean
+ public CacheManager longTermCacheManager(
+ RedisConnectionFactory connectionFactory
+ ) {
+ var _keySerializer = RedisSerializer.string();
+
+ var cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+ .serializeKeysWith(RedisSerializationContext.SerializationPair
+ .fromSerializer(_keySerializer))
+ .serializeValuesWith(RedisSerializationContext.SerializationPair
+ .fromSerializer(JacksonRedisSerialiser.INSTANCE))
+ .entryTtl(Duration.ofDays(1L));
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(connectionFactory)
diff --git a/server/src/main/java/com/onixbyte/ahsarahguide/manager/DailyPasswordManager.java b/server/src/main/java/com/onixbyte/ahsarahguide/manager/DailyPasswordManager.java
index 6686fbb..f622458 100644
--- a/server/src/main/java/com/onixbyte/ahsarahguide/manager/DailyPasswordManager.java
+++ b/server/src/main/java/com/onixbyte/ahsarahguide/manager/DailyPasswordManager.java
@@ -4,20 +4,15 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.onixbyte.ahsarahguide.domain.dto.DailyPasswordResponse;
-import com.onixbyte.ahsarahguide.exeption.InternalServerErrorException;
import com.onixbyte.ahsarahguide.shared.JacksonModules;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
-import org.springframework.http.HttpStatusCode;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.server.ResponseStatusException;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
import java.util.Objects;
/**
@@ -28,15 +23,13 @@ import java.util.Objects;
@Component
public class DailyPasswordManager {
- private static final String CACHE_KEY_PREFIX = "daily-password:";
+ private static final String CACHE_NAME = "daily-password";
private final RestClient restClient;
- private final RedisTemplate