https://github.com/Seungkyu-Han/Toge-do-backend
GitHub - Seungkyu-Han/Toge-do-backend: Toge-do 앱의 백엔드 리포지토리입니다
Toge-do 앱의 백엔드 리포지토리입니다. Contribute to Seungkyu-Han/Toge-do-backend development by creating an account on GitHub.
github.com
우선 에러가 발생한 코드는 다음과 같다.
override fun findByUserId(userId: ObjectId): Mono<PersonalScheduleDocument> {
return reactiveRedisTemplate.opsForValue()
.get("$redisPrefix$userId")
.map{
objectMapper.readValue(it, PersonalScheduleDocument::class.java)
}
.switchIfEmpty(
personalScheduleMongoRepository.findByUserId(userId)
)
.publishOn(Schedulers.boundedElastic())
.doOnSuccess {
if (it != null)
reactiveRedisTemplate.opsForValue()
.set(
"$redisPrefix$userId",
objectMapper.writeValueAsString(it),
personalScheduleRedisTime
).block()
}
}
이렇게 Redis를 먼저 조회하고, 만약 Redis에 값이 없으면 MongoDB를 조회하는 코드이다.
해당 코드를 이용하여 테스트를 하고, Redis에 값이 있으면 MongoDB를 호출하지 않을 것이라고 생각했다.
@Test
@DisplayName("Redis에 조회하려는 값이 있는 경우")
fun findByUserIdAndRedisHaveResultReturnSuccess(){
//given
val userId = ObjectId.get()
val personalSchedule = PersonalScheduleDocument(
userId = userId,
)
val personalScheduleToString = objectMapper.writeValueAsString(personalSchedule)
`when`(reactiveRedisTemplate.opsForValue())
.thenReturn(reactiveValueOperations)
`when`(reactiveValueOperations.get("$redisPrefix$userId"))
.thenReturn(Mono.just(personalScheduleToString))
`when`(personalScheduleMongoRepository.findByUserId(userId))
.thenReturn(Mono.just(personalSchedule))
`when`(reactiveValueOperations.set(
"$redisPrefix$userId",
personalScheduleToString,
personalScheduleRedisTime
)).thenReturn(Mono.just(true))
//when
StepVerifier.create(personalScheduleRepositoryImpl.findByUserId(userId))
.expectNextMatches { it.userId == personalSchedule.userId }.verifyComplete()
//then
verify(personalScheduleMongoRepository, times(0)).findByUserId(userId)
}
이렇게 하고 테스트를 해보았는데
이렇게 MongoDB의 findByUserId가 호출되었다고 나온다.
내가 코드를 작성한 것이라고 생각해서 계속 수정해 보았지만, 고칠 수 없었고 구글링을 통해 답을 얻을 수 있었다.
그냥 원래 그렇다고 한다...
switchIfEmpty가 지금은 데이터베이스에 접근하고 있기 때문에 접근을 최대한 하지 않아야 한다.
그렇기 때문에 Mono.defer를 이용하여 호출을 최대한 미루기로 했다.(defer를 왜 사용하는지 잘 몰랐는데... 여기에서 사용하는구나)
override fun findByUserId(userId: ObjectId): Mono<PersonalScheduleDocument> {
return reactiveRedisTemplate.opsForValue()
.get("$redisPrefix$userId")
.map{
objectMapper.readValue(it, PersonalScheduleDocument::class.java)
}
.switchIfEmpty(
Mono.defer{personalScheduleMongoRepository.findByUserId(userId) }
)
.publishOn(Schedulers.boundedElastic())
.doOnSuccess {
if (it != null)
reactiveRedisTemplate.opsForValue()
.set(
"$redisPrefix$userId",
objectMapper.writeValueAsString(it),
personalScheduleRedisTime
).block()
}
}
이렇게 해당 코드를 Mono.defer{personalScheduleMongoRepository.findByUserId(userId)}로 감싸고 테스트를 해보니
이렇게 테스트가 잘 통과하는 것을 볼 수 있었다.
switchIfEmpty 다 수정하러 가야겠다...
'토이 프로젝트' 카테고리의 다른 글
Spring Webflux + Stomp를 사용해 채팅 구현하기 (0) | 2025.01.05 |
---|---|
MSA에서 Kafka없이 MongoDB만으로 채팅서버 구현하기 (1) | 2025.01.03 |
MSA Gateway에 CircuitBreaker 적용 (0) | 2024.12.16 |
Webflux에 transaction 적용 (0) | 2024.12.13 |
FCM을 사용한 실시간 알림 서비스 (0) | 2024.12.13 |