From da8c12248e39b98db8c73a3429059d82ebf46b2c Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 01:24:23 +0900 Subject: [PATCH 01/30] build(redis): add redis api and standalone module --- core/core.settings.gradle.kts | 6 +++++- core/redis/nettee-redis-api/build.gradle.kts | 3 +++ core/redis/nettee-redis-standalone/build.gradle.kts | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 core/redis/nettee-redis-api/build.gradle.kts create mode 100644 core/redis/nettee-redis-standalone/build.gradle.kts diff --git a/core/core.settings.gradle.kts b/core/core.settings.gradle.kts index ea90957c..ad43458f 100644 --- a/core/core.settings.gradle.kts +++ b/core/core.settings.gradle.kts @@ -15,6 +15,8 @@ include( ":snowflake-id-hibernate", ":client-api", ":rest-client", + ":redis-api", + ":redis-standalone", ) project(":time-util").projectDir = core["time-util"]!! @@ -25,4 +27,6 @@ project(":cors-api").projectDir = core["nettee-cors-api"]!! project(":snowflake-id-api").projectDir = core["nettee-snowflake-id-api"]!! project(":snowflake-id-hibernate").projectDir = core["nettee-snowflake-id-hibernate"]!! project(":client-api").projectDir = core["nettee-client-api"]!! -project(":rest-client").projectDir = core["nettee-rest-client"]!! \ No newline at end of file +project(":rest-client").projectDir = core["nettee-rest-client"]!! +project(":redis-api").projectDir = core["nettee-redis-api"]!! +project(":redis-standalone").projectDir = core["nettee-redis-standalone"]!! \ No newline at end of file diff --git a/core/redis/nettee-redis-api/build.gradle.kts b/core/redis/nettee-redis-api/build.gradle.kts new file mode 100644 index 00000000..ce8ead6f --- /dev/null +++ b/core/redis/nettee-redis-api/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies{ + api("org.springframework.boot:spring-boot-autoconfigure:3.4.3") +} \ No newline at end of file diff --git a/core/redis/nettee-redis-standalone/build.gradle.kts b/core/redis/nettee-redis-standalone/build.gradle.kts new file mode 100644 index 00000000..ca275fb2 --- /dev/null +++ b/core/redis/nettee-redis-standalone/build.gradle.kts @@ -0,0 +1,6 @@ +dependencies{ + api(project(":redis-api")) + + compileOnly("org.springframework.boot:spring-context") + compileOnly("org.springframework.boot:spring-boot-starter-data-redis") +} \ No newline at end of file From 8b04fc3ba20fa3c0694747ea760201c53837ae46 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 01:24:44 +0900 Subject: [PATCH 02/30] feat(redis): add redis properties --- .../redis/properties/RedisProperties.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java new file mode 100644 index 00000000..9ba1a165 --- /dev/null +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -0,0 +1,26 @@ +package nettee.redis.properties; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Slf4j +@ConfigurationProperties("app.redis") +public record RedisProperties( + String host, + Integer port +) { + public RedisProperties { + + if (host == null) { + host = "127.0.0.1"; + log.warn("redis host is null"); + } + + host = host.strip(); + + if (port == null) { + port = 6379; + log.warn("redis port is null"); + } + } +} From 43abc69031aa13d191a4573ea183b4c5319295d9 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 01:25:04 +0900 Subject: [PATCH 03/30] feat(redis): add redis standalone connect factory --- .../redis/config/RedisStandaloneConfig.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java diff --git a/core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java b/core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java new file mode 100644 index 00000000..6be3f88b --- /dev/null +++ b/core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java @@ -0,0 +1,18 @@ +package nettee.redis.config; + +import nettee.redis.properties.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; + +@Configuration +@EnableConfigurationProperties(RedisProperties.class) +public class RedisStandaloneConfig { + + @Bean + public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { + return new LettuceConnectionFactory(redisProperties.host(), redisProperties.port()); + } +} From 7062dff67d4a780dc3e638f727578b2fc7179bc3 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 11:00:37 +0900 Subject: [PATCH 04/30] build(redis): rename redis-standalone to redis core --- core/core.settings.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/core.settings.gradle.kts b/core/core.settings.gradle.kts index ad43458f..3cc395a0 100644 --- a/core/core.settings.gradle.kts +++ b/core/core.settings.gradle.kts @@ -16,7 +16,7 @@ include( ":client-api", ":rest-client", ":redis-api", - ":redis-standalone", + ":redis-core", ) project(":time-util").projectDir = core["time-util"]!! @@ -29,4 +29,4 @@ project(":snowflake-id-hibernate").projectDir = core["nettee-snowflake-id-hibern project(":client-api").projectDir = core["nettee-client-api"]!! project(":rest-client").projectDir = core["nettee-rest-client"]!! project(":redis-api").projectDir = core["nettee-redis-api"]!! -project(":redis-standalone").projectDir = core["nettee-redis-standalone"]!! \ No newline at end of file +project(":redis-core").projectDir = core["nettee-redis-core"]!! \ No newline at end of file From f4198302a660bac609f6c1098b3f6999001876e0 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 11:00:44 +0900 Subject: [PATCH 05/30] build(redis): rename redis-standalone to redis core --- .../build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename core/redis/{nettee-redis-standalone => nettee-redis-core}/build.gradle.kts (66%) diff --git a/core/redis/nettee-redis-standalone/build.gradle.kts b/core/redis/nettee-redis-core/build.gradle.kts similarity index 66% rename from core/redis/nettee-redis-standalone/build.gradle.kts rename to core/redis/nettee-redis-core/build.gradle.kts index ca275fb2..8f7a76e3 100644 --- a/core/redis/nettee-redis-standalone/build.gradle.kts +++ b/core/redis/nettee-redis-core/build.gradle.kts @@ -1,6 +1,5 @@ dependencies{ api(project(":redis-api")) - - compileOnly("org.springframework.boot:spring-context") + compileOnly("org.springframework:spring-context") compileOnly("org.springframework.boot:spring-boot-starter-data-redis") } \ No newline at end of file From 2e7043289b578543d9a85e94bb439e73cf198d0b Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 11:01:51 +0900 Subject: [PATCH 06/30] fix(redis): rename RedisStandaloneConfig to RedisConfig --- .../src/main/java/nettee/redis/config/RedisConfig.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename core/redis/{nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java => nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java} (95%) diff --git a/core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java similarity index 95% rename from core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java rename to core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index 6be3f88b..e2e178c0 100644 --- a/core/redis/nettee-redis-standalone/src/main/java/nettee/redis/config/RedisStandaloneConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -9,7 +9,7 @@ @Configuration @EnableConfigurationProperties(RedisProperties.class) -public class RedisStandaloneConfig { +public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { From bd0fcea305fd2d0b3ea3f3565be9f2ed4a97aa31 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Fri, 30 May 2025 17:56:27 +0900 Subject: [PATCH 07/30] fix(redis): redis add use cluster mode --- .../redis/properties/RedisProperties.java | 25 +++++++++++++------ .../java/nettee/redis/config/RedisConfig.java | 8 +++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index 9ba1a165..ebf3cfda 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -3,24 +3,33 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.List; + @Slf4j @ConfigurationProperties("app.redis") public record RedisProperties( + boolean useClusterMode, String host, - Integer port + List ports ) { public RedisProperties { - + if (!useClusterMode) { + log.info("Redis Connection Mode is Standalone"); + + if(ports.size() > 1) { + throw new RuntimeException("Redis Connection Mode has more than one port"); + } else if(ports.isEmpty()) { + ports.add(6379); + } + } else { + log.info("Redis Connection Mode is Cluster"); + } + if (host == null) { host = "127.0.0.1"; log.warn("redis host is null"); } - + host = host.strip(); - - if (port == null) { - port = 6379; - log.warn("redis port is null"); - } } } diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index e2e178c0..728c497c 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -13,6 +13,12 @@ public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { - return new LettuceConnectionFactory(redisProperties.host(), redisProperties.port()); + if(redisProperties.useClusterMode()) { + // cluster connection + throw new RuntimeException("미구현"); + } else { + // standalone connection + return new LettuceConnectionFactory(redisProperties.host(), redisProperties.ports().getFirst()); + } } } From 47b61dc4bce6930da057117041be968b00538453 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 13:27:59 +0900 Subject: [PATCH 08/30] fix(redis): redis property check validation --- .../main/java/nettee/redis/properties/RedisProperties.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index ebf3cfda..7695f0c0 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -13,13 +13,15 @@ public record RedisProperties( List ports ) { public RedisProperties { + if(ports.isEmpty()) { + ports.add(6379); + } + if (!useClusterMode) { log.info("Redis Connection Mode is Standalone"); if(ports.size() > 1) { throw new RuntimeException("Redis Connection Mode has more than one port"); - } else if(ports.isEmpty()) { - ports.add(6379); } } else { log.info("Redis Connection Mode is Cluster"); From 4f04b0c65ccf174b6a30293416086a64738c10d8 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 13:52:21 +0900 Subject: [PATCH 09/30] feat(redis): redis connect and template bean --- .../java/nettee/redis/config/RedisConfig.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index 728c497c..de1f3828 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -4,8 +4,15 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.util.List; @Configuration @EnableConfigurationProperties(RedisProperties.class) @@ -13,12 +20,36 @@ public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { - if(redisProperties.useClusterMode()) { + if (redisProperties.useClusterMode()) { // cluster connection - throw new RuntimeException("미구현"); + List clusterNodes = + redisProperties.ports().stream() + .map(port -> "%s:%d".formatted(redisProperties.host(), port)) + .toList(); + + return new LettuceConnectionFactory(new RedisClusterConfiguration(clusterNodes)); } else { // standalone connection return new LettuceConnectionFactory(redisProperties.host(), redisProperties.ports().getFirst()); } } + + @Bean + RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + + redisTemplate.setConnectionFactory(connectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer()); + + return redisTemplate; + } + + @Bean + StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) { + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setConnectionFactory(connectionFactory); + + return stringRedisTemplate; + } } From cfb80b046329dc02656b51e0f27ef10934ee785a Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 18:19:52 +0900 Subject: [PATCH 10/30] build(redis): add test library --- core/redis/nettee-redis-api/build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/redis/nettee-redis-api/build.gradle.kts b/core/redis/nettee-redis-api/build.gradle.kts index ce8ead6f..920f5f26 100644 --- a/core/redis/nettee-redis-api/build.gradle.kts +++ b/core/redis/nettee-redis-api/build.gradle.kts @@ -1,3 +1,8 @@ dependencies{ api("org.springframework.boot:spring-boot-autoconfigure:3.4.3") + + // test + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("com.fasterxml.jackson.core:jackson-databind") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin") } \ No newline at end of file From ab41ba5c9fe881dfb7fe356b4a61f3db060e2f2b Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 18:20:16 +0900 Subject: [PATCH 11/30] feat(redis): add cache properties per domain --- .../cache/RedisCacheProperties.java | 24 +++++++++++++++++++ .../cache/domain/DomainCacheProperties.java | 22 +++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java create mode 100644 core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java new file mode 100644 index 00000000..908ac38f --- /dev/null +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java @@ -0,0 +1,24 @@ +package nettee.redis.properties.cache; + +import lombok.extern.slf4j.Slf4j; +import nettee.redis.properties.cache.domain.DomainCacheProperties; + +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +public record RedisCacheProperties( + Map domains +) { + public RedisCacheProperties { + if(domains.isEmpty()) { + log.warn("redis cache domains is empty"); + } + + domains = domains.entrySet().stream() + .collect(Collectors.toMap( + domain -> domain.getKey().strip(), + Map.Entry::getValue + )); + } +} diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java new file mode 100644 index 00000000..d16ad6bc --- /dev/null +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java @@ -0,0 +1,22 @@ +package nettee.redis.properties.cache.domain; + +public record DomainCacheProperties( + long ttl, + Boolean disableNull, + String prefix +) { + public DomainCacheProperties { + // Default 1 minute + if (ttl == 0L) { + ttl = 60L; + } + // Default NO Cache NULL Value + if (disableNull == null) { + disableNull = true; + } + + if (prefix != null) { + prefix = prefix.strip(); + } + } +} From bf4101ccbb6da71d3b183c3efafe38faca76a179 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 18:20:35 +0900 Subject: [PATCH 12/30] feat(redis): add cache properties in redis properties --- .../nettee/redis/properties/RedisProperties.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index 7695f0c0..bde6e587 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -1,6 +1,7 @@ package nettee.redis.properties; import lombok.extern.slf4j.Slf4j; +import nettee.redis.properties.cache.RedisCacheProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.List; @@ -8,16 +9,19 @@ @Slf4j @ConfigurationProperties("app.redis") public record RedisProperties( - boolean useClusterMode, + Boolean useClusterMode, String host, - List ports + List ports, + RedisCacheProperties cache ) { public RedisProperties { - if(ports.isEmpty()) { - ports.add(6379); + if(ports == null || ports.isEmpty()) { + ports = List.of(6379); } - if (!useClusterMode) { + if (useClusterMode == null || !useClusterMode) { + useClusterMode = false; + log.info("Redis Connection Mode is Standalone"); if(ports.size() > 1) { @@ -27,7 +31,7 @@ public record RedisProperties( log.info("Redis Connection Mode is Cluster"); } - if (host == null) { + if (host == null || host.isBlank()) { host = "127.0.0.1"; log.warn("redis host is null"); } From 98649fd3ab16e15aaf631f3b4fabda0712bcc994 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 18:21:04 +0900 Subject: [PATCH 13/30] feat(redis): add test code redis api --- .../nettee/main/RedisApiTestApplication.java | 13 +++ .../redis/properties/RedisPropertiesTest.kt | 110 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 core/redis/nettee-redis-api/src/test/java/nettee/main/RedisApiTestApplication.java create mode 100644 core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt diff --git a/core/redis/nettee-redis-api/src/test/java/nettee/main/RedisApiTestApplication.java b/core/redis/nettee-redis-api/src/test/java/nettee/main/RedisApiTestApplication.java new file mode 100644 index 00000000..de65ce93 --- /dev/null +++ b/core/redis/nettee-redis-api/src/test/java/nettee/main/RedisApiTestApplication.java @@ -0,0 +1,13 @@ +package nettee.main; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; + +@SpringBootApplication +@ConfigurationPropertiesScan(basePackages = "nettee") +public class RedisApiTestApplication { + public static void main(String[] args) { + SpringApplication.run(RedisApiTestApplication.class, args); + } +} diff --git a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt new file mode 100644 index 00000000..e7d9ed37 --- /dev/null +++ b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt @@ -0,0 +1,110 @@ +package nettee.redis.properties + +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FreeSpec +import io.kotest.extensions.spring.SpringExtension +import io.kotest.matchers.shouldBe +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import + +@Import(RedisPropertiesTest.RedisPropertiesTest::class) +class RedisPropertiesTest( + private val redisProperties: RedisProperties +) : FreeSpec({ + + "[초기화 검증] Redis 프로퍼티 검증" - { + "application.yml 모든 변수를 설정했을 때" - { + "useClusterMode는 정상 반환" { + redisProperties.useClusterMode shouldBe true + } + + "host 정상 반환" { + redisProperties.host shouldBe "127.0.0.1" + } + + "ports 정상 반환" { + redisProperties.ports shouldBe listOf(7000, 7001, 7002) + } + + "cache.domains.article 정상 반환" { + val article = redisProperties.cache.domains["article"]!! + article.ttl() shouldBe 300 + article.disableNull() shouldBe true + article.prefix() shouldBe "article::" + } + + "cache.domains.comments 정상 반환" { + val comments = redisProperties.cache.domains["comments"]!! + comments.ttl() shouldBe 60 + comments.disableNull() shouldBe false + comments.prefix() shouldBe "comments::" + } + } + + "application.yml 일부 변수를 누락했을 때" - { + val nullRedisProperties = RedisProperties(null, null, null, null) + + "useClusterMode는 기본값 false 반환" { + nullRedisProperties.useClusterMode shouldBe false + } + + "host는 기본값 127.0.0.1(localhost) 반환" { + nullRedisProperties.host shouldBe "127.0.0.1" + } + + "ports 기본값 [6379] 반환" { + nullRedisProperties.ports shouldBe listOf(6379) + } + } + } + + "[예외 검증] useClusterMode 예외 검증" - { + "useClusterMode가 false(standalone 모드) 일때" - { + "여러 port를 지정하면 에러 반환" { + shouldThrow { + RedisProperties(false, null, listOf(7000, 7001, 7002), null) + } + } + } + } +}) { + override fun extensions() = listOf(SpringExtension) + + @TestConfiguration + class RedisPropertiesTest { + + @Bean + fun redisProperties(): RedisProperties { + val redisYmlJson = """ + { + "useClusterMode": true, + "host": "127.0.0.1", + "ports": [7000, 7001, 7002], + "cache": { + "domains": { + "article": { + "ttl": 300, + "disableNull": true, + "prefix": "article::" + }, + "comments": { + "ttl": 60, + "disableNull": false, + "prefix": "comments::" + } + } + } + } + """.trimIndent() + + val objectMapper = ObjectMapper().registerKotlinModule() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + + return objectMapper.readValue(redisYmlJson, RedisProperties::class.java) + } + } +} From 2eeb210f83b5dfecc994502d52ea414a9a84e3fe Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 22:50:09 +0900 Subject: [PATCH 14/30] refactor(redis): add redis default validation --- .../redis/properties/RedisProperties.java | 20 ++++++++++++++----- .../cache/RedisCacheProperties.java | 15 +++++++------- .../redis/properties/RedisPropertiesTest.kt | 11 ++++++++-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index bde6e587..5a23eb07 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -2,9 +2,11 @@ import lombok.extern.slf4j.Slf4j; import nettee.redis.properties.cache.RedisCacheProperties; +import nettee.redis.properties.cache.domain.DomainCacheProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.List; +import java.util.Map; @Slf4j @ConfigurationProperties("app.redis") @@ -15,7 +17,7 @@ public record RedisProperties( RedisCacheProperties cache ) { public RedisProperties { - if(ports == null || ports.isEmpty()) { + if (ports == null || ports.isEmpty()) { ports = List.of(6379); } @@ -23,19 +25,27 @@ public record RedisProperties( useClusterMode = false; log.info("Redis Connection Mode is Standalone"); - - if(ports.size() > 1) { + + if (ports.size() > 1) { throw new RuntimeException("Redis Connection Mode has more than one port"); } } else { log.info("Redis Connection Mode is Cluster"); } - + if (host == null || host.isBlank()) { host = "127.0.0.1"; log.warn("redis host is null"); } - + host = host.strip(); + + if (cache == null) { + cache = new RedisCacheProperties( + Map.of("app", new DomainCacheProperties(60L, true, "app::")) + ); + + log.warn("Redis cache is null"); + } } } diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java index 908ac38f..248e4bb5 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/RedisCacheProperties.java @@ -11,14 +11,15 @@ public record RedisCacheProperties( Map domains ) { public RedisCacheProperties { - if(domains.isEmpty()) { + if(domains == null || domains.isEmpty()) { log.warn("redis cache domains is empty"); + } else { + domains = domains.entrySet().stream() + .collect(Collectors.toMap( + domain -> domain.getKey().strip(), + Map.Entry::getValue + )); } - - domains = domains.entrySet().stream() - .collect(Collectors.toMap( - domain -> domain.getKey().strip(), - Map.Entry::getValue - )); + } } diff --git a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt index e7d9ed37..1466427b 100644 --- a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt +++ b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt @@ -16,7 +16,7 @@ class RedisPropertiesTest( private val redisProperties: RedisProperties ) : FreeSpec({ - "[초기화 검증] Redis 프로퍼티 검증" - { + "[초기화 검증] Redis 설정 값을 반환" - { "application.yml 모든 변수를 설정했을 때" - { "useClusterMode는 정상 반환" { redisProperties.useClusterMode shouldBe true @@ -59,10 +59,17 @@ class RedisPropertiesTest( "ports 기본값 [6379] 반환" { nullRedisProperties.ports shouldBe listOf(6379) } + + "cache 기본값 cache 반환" { + val app = nullRedisProperties.cache.domains["app"]!! + app.ttl() shouldBe 60 + app.disableNull() shouldBe true + app.prefix() shouldBe "app::" + } } } - "[예외 검증] useClusterMode 예외 검증" - { + "[예외 검증] useClusterMode 예외 반환" - { "useClusterMode가 false(standalone 모드) 일때" - { "여러 port를 지정하면 에러 반환" { shouldThrow { From 5e82a8befb89471ee3d4b279f8bb1eeb19ded4c8 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 22:50:38 +0900 Subject: [PATCH 15/30] feat(redis): add redis cache manager bean --- .../java/nettee/redis/config/RedisConfig.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index de1f3828..fefb723c 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -4,6 +4,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; @@ -12,7 +14,10 @@ import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import java.time.Duration; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Configuration @EnableConfigurationProperties(RedisProperties.class) @@ -52,4 +57,33 @@ StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory return stringRedisTemplate; } + + @Bean + public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, RedisProperties redisProperties) { + // 도메인 별 캐시 적용 + Map domainCacheConfigurations = redisProperties.cache().domains().entrySet().stream() + .collect(Collectors.toMap( + // 도메인명 (ex: article) + Map.Entry::getKey, + entry -> { + var domainCacheProperties = entry.getValue(); + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofSeconds(domainCacheProperties.ttl())); + + if (domainCacheProperties.disableNull()) { + config = config.disableCachingNullValues(); + } + + config = config.computePrefixWith(cacheName -> domainCacheProperties.prefix()); + + return config; + } + )); + + return RedisCacheManager.builder(connectionFactory) + .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()) + .transactionAware() + .withInitialCacheConfigurations(domainCacheConfigurations) + .build(); + } } From b8547f115f59ecf67752111504bfa5c8d51269f0 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Sat, 31 May 2025 22:57:17 +0900 Subject: [PATCH 16/30] feat(redis): add EnableCaching annotation --- .../src/main/java/nettee/redis/config/RedisConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index fefb723c..b6c3ab4f 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -2,6 +2,7 @@ import nettee.redis.properties.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; @@ -20,6 +21,7 @@ import java.util.stream.Collectors; @Configuration +@EnableCaching @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig { From b63723b0b0b57d57ba3778a5a8f5bd0f2d61ef1b Mon Sep 17 00:00:00 2001 From: merge-simpson Date: Mon, 2 Jun 2025 02:47:40 +0900 Subject: [PATCH 17/30] style(core): remove one of continuous blank lines --- core/core.settings.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/core.settings.gradle.kts b/core/core.settings.gradle.kts index 3cc395a0..0bb36ed5 100644 --- a/core/core.settings.gradle.kts +++ b/core/core.settings.gradle.kts @@ -4,7 +4,6 @@ val core = rootDir.resolve("core") .filter(File::isDirectory) .associateBy(File::getName) - include( ":time-util", ":jpa-core", From e7bdf5a063a9d74b3980cb533cdf181d8c0a1661 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Mon, 2 Jun 2025 13:55:37 +0900 Subject: [PATCH 18/30] fix(redis): fix redis properties validate --- .../nettee/redis/properties/RedisProperties.java | 2 +- .../cache/domain/DomainCacheProperties.java | 12 ++++++++---- .../nettee/redis/properties/RedisPropertiesTest.kt | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index 5a23eb07..e35fcc18 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -42,7 +42,7 @@ public record RedisProperties( if (cache == null) { cache = new RedisCacheProperties( - Map.of("app", new DomainCacheProperties(60L, true, "app::")) + Map.of("app", new DomainCacheProperties(null, null, null)) ); log.warn("Redis cache is null"); diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java index d16ad6bc..d5217ed5 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java @@ -1,22 +1,26 @@ package nettee.redis.properties.cache.domain; public record DomainCacheProperties( - long ttl, + Long ttl, Boolean disableNull, String prefix ) { public DomainCacheProperties { // Default 1 minute - if (ttl == 0L) { + if (ttl == null) { ttl = 60L; + }else if(ttl < 0) { + throw new RuntimeException("TTL is set to 'no expiration'. The entry will not expire."); } // Default NO Cache NULL Value if (disableNull == null) { disableNull = true; } - if (prefix != null) { - prefix = prefix.strip(); + if (prefix == null) { + prefix = ""; } + + prefix = prefix.strip(); } } diff --git a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt index 1466427b..4cabde11 100644 --- a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt +++ b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt @@ -64,7 +64,7 @@ class RedisPropertiesTest( val app = nullRedisProperties.cache.domains["app"]!! app.ttl() shouldBe 60 app.disableNull() shouldBe true - app.prefix() shouldBe "app::" + app.prefix() shouldBe "" } } } From f9f76b91507adc7f0a13c42c9c0a9b80f9905965 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Mon, 2 Jun 2025 16:13:45 +0900 Subject: [PATCH 19/30] build(redis): remove version spring boot autoconfigure --- core/redis/nettee-redis-api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/redis/nettee-redis-api/build.gradle.kts b/core/redis/nettee-redis-api/build.gradle.kts index 920f5f26..9c130d5e 100644 --- a/core/redis/nettee-redis-api/build.gradle.kts +++ b/core/redis/nettee-redis-api/build.gradle.kts @@ -1,5 +1,5 @@ dependencies{ - api("org.springframework.boot:spring-boot-autoconfigure:3.4.3") + api("org.springframework.boot:spring-boot-autoconfigure") // test testImplementation("org.springframework.boot:spring-boot-starter-test") From b4ae42e4a9c48248c7e111c4c77ecfdf2bd8fbcc Mon Sep 17 00:00:00 2001 From: silberbullet Date: Mon, 2 Jun 2025 16:14:19 +0900 Subject: [PATCH 20/30] refactor(redis): change nodes from host and port --- .../redis/properties/RedisProperties.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java index e35fcc18..e48f1367 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/RedisProperties.java @@ -12,34 +12,30 @@ @ConfigurationProperties("app.redis") public record RedisProperties( Boolean useClusterMode, - String host, - List ports, + List nodes, RedisCacheProperties cache ) { public RedisProperties { - if (ports == null || ports.isEmpty()) { - ports = List.of(6379); + if (nodes == null || nodes.isEmpty()) { + nodes = List.of("localhost:6379"); + + log.warn("redis nodes is null"); } - + + nodes = nodes.stream().map(String::strip).toList(); + if (useClusterMode == null || !useClusterMode) { useClusterMode = false; log.info("Redis Connection Mode is Standalone"); - if (ports.size() > 1) { - throw new RuntimeException("Redis Connection Mode has more than one port"); + if (nodes.size() > 1) { + throw new RuntimeException("More than one Redis node is configured in standalone mode"); } } else { log.info("Redis Connection Mode is Cluster"); } - if (host == null || host.isBlank()) { - host = "127.0.0.1"; - log.warn("redis host is null"); - } - - host = host.strip(); - if (cache == null) { cache = new RedisCacheProperties( Map.of("app", new DomainCacheProperties(null, null, null)) From f25e84f3c90075d00f2a4c5c5dbd3b54ed16c3f2 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Mon, 2 Jun 2025 16:14:43 +0900 Subject: [PATCH 21/30] fix(redis): fix redis property test code --- .../redis/properties/RedisPropertiesTest.kt | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt index 4cabde11..eb1c8cef 100644 --- a/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt +++ b/core/redis/nettee-redis-api/src/test/kotlin/nettee/redis/properties/RedisPropertiesTest.kt @@ -22,12 +22,8 @@ class RedisPropertiesTest( redisProperties.useClusterMode shouldBe true } - "host 정상 반환" { - redisProperties.host shouldBe "127.0.0.1" - } - - "ports 정상 반환" { - redisProperties.ports shouldBe listOf(7000, 7001, 7002) + "nodes 정상 반환" { + redisProperties.nodes.size shouldBe 3 } "cache.domains.article 정상 반환" { @@ -46,18 +42,14 @@ class RedisPropertiesTest( } "application.yml 일부 변수를 누락했을 때" - { - val nullRedisProperties = RedisProperties(null, null, null, null) + val nullRedisProperties = RedisProperties(null, null, null) "useClusterMode는 기본값 false 반환" { nullRedisProperties.useClusterMode shouldBe false } - "host는 기본값 127.0.0.1(localhost) 반환" { - nullRedisProperties.host shouldBe "127.0.0.1" - } - - "ports 기본값 [6379] 반환" { - nullRedisProperties.ports shouldBe listOf(6379) + "nodes 기본값 localhost:6379 반환" { + nullRedisProperties.nodes[0] shouldBe "localhost:6379" } "cache 기본값 cache 반환" { @@ -71,9 +63,9 @@ class RedisPropertiesTest( "[예외 검증] useClusterMode 예외 반환" - { "useClusterMode가 false(standalone 모드) 일때" - { - "여러 port를 지정하면 에러 반환" { + "node가 다건이면 에러 반환" { shouldThrow { - RedisProperties(false, null, listOf(7000, 7001, 7002), null) + RedisProperties(false, listOf("localhost:7001", "localhost:7002"), null) } } } @@ -89,8 +81,7 @@ class RedisPropertiesTest( val redisYmlJson = """ { "useClusterMode": true, - "host": "127.0.0.1", - "ports": [7000, 7001, 7002], + "nodes": ["localhost:7000", "localhost:7001", "localhost:7002"], "cache": { "domains": { "article": { From f1ab79abdae825a870f25a24958face17c993b57 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Mon, 2 Jun 2025 16:15:27 +0900 Subject: [PATCH 22/30] refactor(redis): add nodes in redis config --- .../main/java/nettee/redis/config/RedisConfig.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java index b6c3ab4f..dd72cbaa 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java @@ -16,7 +16,6 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -29,15 +28,12 @@ public class RedisConfig { public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { if (redisProperties.useClusterMode()) { // cluster connection - List clusterNodes = - redisProperties.ports().stream() - .map(port -> "%s:%d".formatted(redisProperties.host(), port)) - .toList(); - - return new LettuceConnectionFactory(new RedisClusterConfiguration(clusterNodes)); + return new LettuceConnectionFactory(new RedisClusterConfiguration(redisProperties.nodes())); } else { // standalone connection - return new LettuceConnectionFactory(redisProperties.host(), redisProperties.ports().getFirst()); + var node = redisProperties.nodes().getFirst().split(":"); + + return new LettuceConnectionFactory(node[0], Integer.parseInt(node[1])); } } From 1502fa49c9576b613049623a7b13afd7005e8ac5 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:18:41 +0900 Subject: [PATCH 23/30] build(redis): classify redis core to redis template and cache --- core/core.settings.gradle.kts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/core.settings.gradle.kts b/core/core.settings.gradle.kts index 0bb36ed5..90ef71ac 100644 --- a/core/core.settings.gradle.kts +++ b/core/core.settings.gradle.kts @@ -15,7 +15,8 @@ include( ":client-api", ":rest-client", ":redis-api", - ":redis-core", + ":redis-template", + ":redis-cache", ) project(":time-util").projectDir = core["time-util"]!! @@ -28,4 +29,5 @@ project(":snowflake-id-hibernate").projectDir = core["nettee-snowflake-id-hibern project(":client-api").projectDir = core["nettee-client-api"]!! project(":rest-client").projectDir = core["nettee-rest-client"]!! project(":redis-api").projectDir = core["nettee-redis-api"]!! -project(":redis-core").projectDir = core["nettee-redis-core"]!! \ No newline at end of file +project(":redis-template").projectDir = core["nettee-redis-template"]!! +project(":redis-cache").projectDir = core["nettee-redis-cache"]!! \ No newline at end of file From b2f3f4ba1865a33e86910f6d0cd2a0a48676e3e4 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:19:24 +0900 Subject: [PATCH 24/30] build(redis): add spring data redis library in api module --- core/redis/nettee-redis-api/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/redis/nettee-redis-api/build.gradle.kts b/core/redis/nettee-redis-api/build.gradle.kts index 9c130d5e..5f383547 100644 --- a/core/redis/nettee-redis-api/build.gradle.kts +++ b/core/redis/nettee-redis-api/build.gradle.kts @@ -1,6 +1,7 @@ dependencies{ api("org.springframework.boot:spring-boot-autoconfigure") - + api("org.springframework.boot:spring-boot-starter-data-redis") + compileOnly("org.springframework:spring-context") // test testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("com.fasterxml.jackson.core:jackson-databind") From d892992264bfb5fb592ce67824b5e690008df976 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:22:17 +0900 Subject: [PATCH 25/30] feat(redis): add base RedisConnectionFactory bean to redis-api module cuz is api --- .../redis/config/RedisConnectionConfig.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 core/redis/nettee-redis-api/src/main/java/nettee/redis/config/RedisConnectionConfig.java diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/config/RedisConnectionConfig.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/config/RedisConnectionConfig.java new file mode 100644 index 00000000..d485a64b --- /dev/null +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/config/RedisConnectionConfig.java @@ -0,0 +1,27 @@ +package nettee.redis.config; + +import nettee.redis.properties.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; + +@Configuration +@EnableConfigurationProperties(RedisProperties.class) +public class RedisConnectionConfig { + + @Bean + public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { + if (redisProperties.useClusterMode()) { + // cluster connection + return new LettuceConnectionFactory(new RedisClusterConfiguration(redisProperties.nodes())); + } else { + // standalone connection + var node = redisProperties.nodes().getFirst().split(":"); + + return new LettuceConnectionFactory(node[0], Integer.parseInt(node[1])); + } + } +} From 7abb99e3e35f9a6c3bf22e61b8396efe7b8b4d6a Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:22:44 +0900 Subject: [PATCH 26/30] chore(redis): delete redis core directory --- core/redis/nettee-redis-core/build.gradle.kts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 core/redis/nettee-redis-core/build.gradle.kts diff --git a/core/redis/nettee-redis-core/build.gradle.kts b/core/redis/nettee-redis-core/build.gradle.kts deleted file mode 100644 index 8f7a76e3..00000000 --- a/core/redis/nettee-redis-core/build.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -dependencies{ - api(project(":redis-api")) - compileOnly("org.springframework:spring-context") - compileOnly("org.springframework.boot:spring-boot-starter-data-redis") -} \ No newline at end of file From d4e335ddec3c60260a4ae63cbf949a0fd135c1e4 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:23:12 +0900 Subject: [PATCH 27/30] feat(redis): add redis template module --- .../nettee-redis-template/build.gradle.kts | 3 ++ .../redis/config/RedisTemplateConfig.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 core/redis/nettee-redis-template/build.gradle.kts create mode 100644 core/redis/nettee-redis-template/src/main/java/nettee/redis/config/RedisTemplateConfig.java diff --git a/core/redis/nettee-redis-template/build.gradle.kts b/core/redis/nettee-redis-template/build.gradle.kts new file mode 100644 index 00000000..22035925 --- /dev/null +++ b/core/redis/nettee-redis-template/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies{ + api(project(":redis-api")) +} \ No newline at end of file diff --git a/core/redis/nettee-redis-template/src/main/java/nettee/redis/config/RedisTemplateConfig.java b/core/redis/nettee-redis-template/src/main/java/nettee/redis/config/RedisTemplateConfig.java new file mode 100644 index 00000000..f297f324 --- /dev/null +++ b/core/redis/nettee-redis-template/src/main/java/nettee/redis/config/RedisTemplateConfig.java @@ -0,0 +1,32 @@ +package nettee.redis.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisTemplateConfig { + + @Bean + RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + + redisTemplate.setConnectionFactory(connectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer()); + + return redisTemplate; + } + + @Bean + StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) { + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setConnectionFactory(connectionFactory); + + return stringRedisTemplate; + } +} From 589e09bc57195fd9fef4ab321e007f4b69f3ee75 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:23:23 +0900 Subject: [PATCH 28/30] feat(redis): add redis cache module --- .../redis/nettee-redis-cache/build.gradle.kts | 3 ++ .../redis/config/RedisCacheConfig.java} | 41 +------------------ 2 files changed, 4 insertions(+), 40 deletions(-) create mode 100644 core/redis/nettee-redis-cache/build.gradle.kts rename core/redis/{nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java => nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java} (55%) diff --git a/core/redis/nettee-redis-cache/build.gradle.kts b/core/redis/nettee-redis-cache/build.gradle.kts new file mode 100644 index 00000000..22035925 --- /dev/null +++ b/core/redis/nettee-redis-cache/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies{ + api(project(":redis-api")) +} \ No newline at end of file diff --git a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java similarity index 55% rename from core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java rename to core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java index dd72cbaa..901384ea 100644 --- a/core/redis/nettee-redis-core/src/main/java/nettee/redis/config/RedisConfig.java +++ b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java @@ -7,13 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; -import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; import java.util.Map; @@ -22,40 +16,7 @@ @Configuration @EnableCaching @EnableConfigurationProperties(RedisProperties.class) -public class RedisConfig { - - @Bean - public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { - if (redisProperties.useClusterMode()) { - // cluster connection - return new LettuceConnectionFactory(new RedisClusterConfiguration(redisProperties.nodes())); - } else { - // standalone connection - var node = redisProperties.nodes().getFirst().split(":"); - - return new LettuceConnectionFactory(node[0], Integer.parseInt(node[1])); - } - } - - @Bean - RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate<>(); - - redisTemplate.setConnectionFactory(connectionFactory); - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer()); - - return redisTemplate; - } - - @Bean - StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) { - StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); - stringRedisTemplate.setConnectionFactory(connectionFactory); - - return stringRedisTemplate; - } - +public class RedisCacheConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, RedisProperties redisProperties) { // 도메인 별 캐시 적용 From 9e399cc0e2bcc69de778b16737ebf929b17ee299 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:24:00 +0900 Subject: [PATCH 29/30] chore(redis): add blank line --- .../src/main/java/nettee/redis/config/RedisCacheConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java index 901384ea..c0d6b2e9 100644 --- a/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java +++ b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java @@ -17,6 +17,7 @@ @EnableCaching @EnableConfigurationProperties(RedisProperties.class) public class RedisCacheConfig { + @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, RedisProperties redisProperties) { // 도메인 별 캐시 적용 From cba62ca6914b113d38688d25976a847d3cc6ba00 Mon Sep 17 00:00:00 2001 From: silberbullet Date: Tue, 3 Jun 2025 15:46:46 +0900 Subject: [PATCH 30/30] refactor(redis): ttl fix for expire --- .../properties/cache/domain/DomainCacheProperties.java | 10 ++++------ .../java/nettee/redis/config/RedisCacheConfig.java | 7 +++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java index d5217ed5..0c823305 100644 --- a/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java +++ b/core/redis/nettee-redis-api/src/main/java/nettee/redis/properties/cache/domain/DomainCacheProperties.java @@ -6,12 +6,10 @@ public record DomainCacheProperties( String prefix ) { public DomainCacheProperties { - // Default 1 minute - if (ttl == null) { - ttl = 60L; - }else if(ttl < 0) { - throw new RuntimeException("TTL is set to 'no expiration'. The entry will not expire."); + if(ttl != null && ttl < 0L) { + throw new IllegalArgumentException("TTL must be zero or a positive number. Negative TTL is not allowed."); } + // Default NO Cache NULL Value if (disableNull == null) { disableNull = true; @@ -20,7 +18,7 @@ public record DomainCacheProperties( if (prefix == null) { prefix = ""; } - + prefix = prefix.strip(); } } diff --git a/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java index c0d6b2e9..73a8d5f9 100644 --- a/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java +++ b/core/redis/nettee-redis-cache/src/main/java/nettee/redis/config/RedisCacheConfig.java @@ -27,8 +27,11 @@ public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, Map.Entry::getKey, entry -> { var domainCacheProperties = entry.getValue(); - RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofSeconds(domainCacheProperties.ttl())); + var config = RedisCacheConfiguration.defaultCacheConfig(); + + if(domainCacheProperties.ttl() != null){ + config = config.entryTtl(Duration.ofSeconds(domainCacheProperties.ttl())); + } if (domainCacheProperties.disableNull()) { config = config.disableCachingNullValues();