Skip to content

Commit f400858

Browse files
authored
Merge pull request #99 from NMNB-Team/v1/fix/#98-change-invalidate-cache
[refactor] 캐시 만료 시간 제거 및 조건부 재설정으로 변경
2 parents d914199 + b53382b commit f400858

7 files changed

Lines changed: 105 additions & 3 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package nmnb.application.domain.post.service
2+
3+
import org.springframework.cache.annotation.CacheEvict
4+
import org.springframework.stereotype.Service
5+
6+
@Service
7+
class PostCacheEvictor() {
8+
@CacheEvict(cacheNames = ["postIds"])
9+
fun refreshPostIds() {
10+
}
11+
12+
@CacheEvict(cacheNames = ["shuffledIds"], key = "#seed")
13+
fun refreshShuffledIds(seed: Int) {
14+
}
15+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package nmnb.application.domain.post.service
22

3+
import nmnb.application.domain.post.service.dto.request.PostPageServiceRequest
4+
35
interface PostCacheService {
46
fun getAllPostIds(): List<Long>
57
fun getShuffledIds(ids: List<Long>, seed: Int): List<Long>
8+
fun refreshPostcache(request: PostPageServiceRequest)
69
}

nmnb-application/src/main/kotlin/nmnb/application/domain/post/service/PostCacheServiceImpl.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package nmnb.application.domain.post.service
22

3+
import nmnb.application.domain.post.service.dto.request.PostPageServiceRequest
34
import nmnb.application.domain.post.utils.RandomSelector
45
import nmnb.domain.post.repository.PostRepository
56
import org.springframework.cache.annotation.Cacheable
@@ -8,6 +9,7 @@ import org.springframework.stereotype.Service
89
@Service
910
class PostCacheServiceImpl(
1011
private val postRepository: PostRepository,
12+
private val postCacheEvictor: PostCacheEvictor,
1113
) : PostCacheService {
1214
@Cacheable(cacheNames = ["postIds"])
1315
override fun getAllPostIds(): List<Long> = postRepository.findAllPostId()
@@ -16,4 +18,15 @@ class PostCacheServiceImpl(
1618
override fun getShuffledIds(ids: List<Long>, seed: Int): List<Long> {
1719
return RandomSelector.shuffleIds(ids, seed)
1820
}
21+
22+
override fun refreshPostcache(request: PostPageServiceRequest) {
23+
if (request.cursor == INITIAL_CURSOR) {
24+
postCacheEvictor.refreshPostIds()
25+
postCacheEvictor.refreshShuffledIds(request.seed)
26+
}
27+
}
28+
29+
companion object {
30+
private const val INITIAL_CURSOR = -1
31+
}
1932
}

nmnb-application/src/main/kotlin/nmnb/application/domain/post/service/PostServiceImpl.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class PostServiceImpl(
1616
private val postCacheService: PostCacheService,
1717
) : PostService {
1818
override fun getPostPage(request: PostPageServiceRequest): PostPageResponse {
19+
postCacheService.refreshPostcache(request)
1920
val allPostIds = postCacheService.getAllPostIds()
2021
val shuffledPostIds = postCacheService.getShuffledIds(allPostIds, request.seed)
2122

@@ -32,7 +33,7 @@ class PostServiceImpl(
3233
): PostPageResponse {
3334
val postsInfoResponse = mapPostsToResponse(pageIds)
3435
val hasNext = shuffledPostIds.size > (startIndex + pageIds.size)
35-
val nextCursor = if (!hasNext) -1 else startIndex + pageIds.size - 1
36+
val nextCursor = if (!hasNext) INITIAL_CURSOR else startIndex + pageIds.size - 1
3637

3738
return PostPageResponse.of(postsInfoResponse, hasNext, nextCursor)
3839
}
@@ -48,4 +49,8 @@ class PostServiceImpl(
4849
val posts = postRepository.findAllByIdIn(pageIds)
4950
return posts.associateBy { it.id!! }
5051
}
52+
53+
companion object {
54+
private const val INITIAL_CURSOR = -1
55+
}
5156
}

nmnb-application/src/main/kotlin/nmnb/application/global/config/CacheConfig.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import org.springframework.cache.annotation.EnableCaching
66
import org.springframework.cache.caffeine.CaffeineCacheManager
77
import org.springframework.context.annotation.Bean
88
import org.springframework.context.annotation.Configuration
9-
import java.util.concurrent.TimeUnit
109

1110
@EnableCaching
1211
@Configuration
@@ -16,7 +15,6 @@ class CacheConfig {
1615
val cacheManager = CaffeineCacheManager()
1716
cacheManager.setCaffeine(
1817
Caffeine.newBuilder()
19-
.expireAfterWrite(10, TimeUnit.MINUTES)
2018
.maximumSize(100),
2119
)
2220
return cacheManager

nmnb-application/src/test/kotlin/nmnb/application/domain/post/service/PostCacheServiceTest.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package nmnb.application.domain.post.service
22

33
import nmnb.application.IntegrationTestSupport
4+
import nmnb.application.domain.post.service.dto.request.PostPageServiceRequest
45
import nmnb.domain.post.repository.PostRepository
56
import org.assertj.core.api.Assertions.assertThat
7+
import org.junit.jupiter.api.AfterEach
68
import org.junit.jupiter.api.DisplayName
79
import org.junit.jupiter.api.Test
810
import org.junit.jupiter.api.extension.ExtendWith
@@ -20,11 +22,19 @@ class PostCacheServiceTest(
2022
@Autowired
2123
var postCacheService: PostCacheService,
2224
@Autowired
25+
var postCacheEvictor: PostCacheEvictor,
26+
@Autowired
2327
var cacheManager: CacheManager,
2428
) : IntegrationTestSupport() {
2529
@MockBean
2630
lateinit var postRepository: PostRepository
2731

32+
@AfterEach
33+
fun tearDown() {
34+
cacheManager.getCache("postIds")?.clear()
35+
cacheManager.getCache("shuffledIds")?.clear()
36+
}
37+
2838
@DisplayName("getAllPostIds 메서드는 캐시에 저장되며, 두 번째 호출부터는 캐시된 값이 반환된다")
2939
@Test
3040
fun getAllPostIdsWithCache() {
@@ -64,4 +74,27 @@ class PostCacheServiceTest(
6474
assertThat(result1).isEqualTo(result2)
6575
assertThat(result1).isNotEqualTo(result3)
6676
}
77+
78+
@DisplayName("캐시를 무효화하는데 성공한다.")
79+
@Test
80+
fun refreshCache() {
81+
// given
82+
val ids = listOf(1L, 2L, 3L, 4L, 5L)
83+
whenever(postRepository.findAllPostId()).thenReturn(ids)
84+
val seed = 1234
85+
val request = PostPageServiceRequest(seed = seed, cursor = -1, size = 7)
86+
87+
postCacheService.getAllPostIds()
88+
postCacheService.getShuffledIds(ids, seed)
89+
90+
assertThat(cacheManager.getCache("postIds")?.get(SimpleKey.EMPTY)).isNotNull
91+
assertThat(cacheManager.getCache("shuffledIds")?.get(seed)).isNotNull
92+
93+
// when
94+
postCacheService.refreshPostcache(request)
95+
96+
// then
97+
assertThat(cacheManager.getCache("postIds")?.get(SimpleKey.EMPTY)).isNull()
98+
assertThat(cacheManager.getCache("shuffledIds")?.get(seed)).isNull()
99+
}
67100
}

nmnb-application/src/test/kotlin/nmnb/application/domain/post/service/PostServiceImplTest.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import org.assertj.core.api.Assertions.assertThat
1010
import org.junit.jupiter.api.AfterEach
1111
import org.junit.jupiter.api.DisplayName
1212
import org.junit.jupiter.api.Test
13+
import org.mockito.kotlin.never
14+
import org.mockito.kotlin.times
15+
import org.mockito.kotlin.verify
1316
import org.springframework.beans.factory.annotation.Autowired
17+
import org.springframework.boot.test.mock.mockito.MockBean
1418
import org.springframework.cache.CacheManager
1519
import org.springframework.transaction.annotation.Transactional
1620

@@ -22,6 +26,9 @@ class PostServiceImplTest(
2226
@Autowired private var cacheManager: CacheManager,
2327
) : IntegrationTestSupport() {
2428

29+
@MockBean
30+
private lateinit var postCacheEvictor: PostCacheEvictor
31+
2532
@AfterEach
2633
fun tearDown() {
2734
postRepository.deleteAllInBatch()
@@ -89,4 +96,32 @@ class PostServiceImplTest(
8996
// then
9097
assertThat(result.nextCursor).isEqualTo(-1)
9198
}
99+
100+
@DisplayName("조회 커서가 초기 값(-1)일 경우 캐시가 무효화된다.")
101+
@Test
102+
fun refreshCacheWhenInitialCursor() {
103+
// given
104+
val seed = 1234
105+
val request = PostPageServiceRequest(seed = seed, cursor = -1, size = 7)
106+
107+
// when
108+
postService.getPostPage(request)
109+
110+
// then
111+
verify(postCacheEvictor, times(1)).refreshPostIds()
112+
}
113+
114+
@DisplayName("조회 커서가 초기 값(-1)이 아닐 경우 캐시가 무효화되지 않는다.")
115+
@Test
116+
fun refreshCacheWhenNotInitialCursor() {
117+
// given
118+
val seed = 1234
119+
val request = PostPageServiceRequest(seed = seed, cursor = 1, size = 7)
120+
121+
// when
122+
postService.getPostPage(request)
123+
124+
// then
125+
verify(postCacheEvictor, never()).refreshPostIds()
126+
}
92127
}

0 commit comments

Comments
 (0)