Skip to content

Commit

Permalink
PO-439: Integrate Redis cache for opal-fines-service
Browse files Browse the repository at this point in the history
Add logging for Redis details
  • Loading branch information
sabahirfan authored and RustyHMCTS committed Aug 22, 2024
1 parent 534d44a commit 4faa95e
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 1 deletion.
104 changes: 104 additions & 0 deletions src/main/java/uk/gov/hmcts/opal/cache/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package uk.gov.hmcts.opal.cache;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
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;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;

import java.time.Duration;

@Slf4j
@Configuration
@EnableCaching
public class CacheConfig {

@Value("${opal.redis.enabled}")
private boolean redisEnabled;

@Value("${spring.data.redis.host}")
private String redisHost;

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

@Value("${opal.redis.ttl-hours}")
private long redisTtlHours;

private CacheManager cacheManager;

@Bean
@ConditionalOnProperty(name = "opal.redis.enabled", havingValue = "true")
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
return new LettuceConnectionFactory(config);
}

@Bean
@ConditionalOnProperty(name = "opal.redis.enabled", havingValue = "true")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

@Bean
@Primary
@ConditionalOnProperty(name = "opal.redis.enabled", havingValue = "true")
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(redisTtlHours))
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

this.cacheManager = RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(cacheConfig)
.build();
logCacheDetails(cacheManager);
return cacheManager;
}

@Bean
@ConditionalOnProperty(name = "opal.redis.enabled", havingValue = "false", matchIfMissing = true)
public CacheManager simpleCacheManager() {
this.cacheManager = new ConcurrentMapCacheManager();
logCacheDetails(cacheManager);
return cacheManager;
}

public void logCacheDetails(CacheManager cacheManager) {
log.info("------------------------------");
log.info("Cache Configuration Details:");
log.info("Redis Enabled: {}", redisEnabled);
log.info("Redis Host: {}", redisHost);
log.info("Redis Port: {}", redisPort);
log.info("Redis TTL (hours): {}", redisTtlHours);
if (cacheManager != null) {
log.info("Cache Manager: {}", cacheManager.getClass().getName());
if (cacheManager instanceof RedisCacheManager) {
log.info("Using Redis Cache Manager");
} else if (cacheManager instanceof ConcurrentMapCacheManager) {
log.info("Using Concurrent Map Cache Manager (local cache)");
}
} else {
log.warn("Cache Manager is null. This might indicate a configuration issue.");
}

log.info("Available Caches:");
if (cacheManager != null) {
cacheManager.getCacheNames().forEach(cacheName -> log.info("- {}", cacheName));
}
log.info("------------------------------");
}
}
2 changes: 1 addition & 1 deletion src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ opal:
file-handler-job:
cron: ${OPAL_FILE_HANDLER_JOB_CRON:0 0 * * * ?}
frontend:
url: ${OPAL_FRONTEND_URL:http://localhost:4200}
url: ${OPAL_FRONTEND_URL:http://localhost:4200}
azure:
active-directory-justice-auth-uri: https://login.microsoftonline.com
testing-support-endpoints:
Expand Down
68 changes: 68 additions & 0 deletions src/test/java/uk/gov/hmcts/opal/cache/CacheConfigTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package uk.gov.hmcts.opal.cache;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;

@SpringBootTest(classes = {CacheConfig.class, CacheConfigTest.TestConfig.class})
class CacheConfigTest {

@Autowired
private CacheManager cacheManager;

@Autowired
private RedisConnectionFactory redisConnectionFactory;

@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.redis.host", () -> "localhost");
registry.add("spring.data.redis.port", () -> "6379");
registry.add("opal.redis.ttl.hours", () -> "8");
registry.add("opal.redis.enabled", () -> "false");
}

@Test
void whenRedisEnabled_thenReturnRedisCacheManager() {
assertTrue(cacheManager instanceof RedisCacheManager);
}

@Test
void whenRedisDisabled_thenReturnSimpleCacheManager() {
CacheConfig config = new CacheConfig();
CacheManager simpleCacheManager = config.simpleCacheManager();
assertTrue(simpleCacheManager instanceof ConcurrentMapCacheManager);
}

@Test
void testRedisConnectionFactory() {
assertNotNull(redisConnectionFactory);
}

@TestConfiguration
static class TestConfig {
@Bean
@Primary
public RedisConnectionFactory redisConnectionFactory() {
return mock(RedisConnectionFactory.class);
}

@Bean
@Primary
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory).build();
}
}
}

0 comments on commit 4faa95e

Please sign in to comment.