From a5dd01535df748c4032298e5c3a422994b8b5c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Wed, 2 Oct 2024 00:10:38 +0900 Subject: [PATCH] =?UTF-8?q?[Refactor]:=20=EB=9E=AD=ED=82=B9=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=201,7,30=EC=9C=BC=EB=A1=9C=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../novel/domain/NovelRankingSearchDays.kt | 14 ++++++++++++++ .../novel/domain/application/NovelQueryService.kt | 11 ++++++----- .../novelcia/novel/interfaces/NovelController.kt | 7 +++++-- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/com/reditus/novelcia/novel/domain/NovelRankingSearchDays.kt diff --git a/src/main/kotlin/com/reditus/novelcia/novel/domain/NovelRankingSearchDays.kt b/src/main/kotlin/com/reditus/novelcia/novel/domain/NovelRankingSearchDays.kt new file mode 100644 index 0000000..f562985 --- /dev/null +++ b/src/main/kotlin/com/reditus/novelcia/novel/domain/NovelRankingSearchDays.kt @@ -0,0 +1,14 @@ +package com.reditus.novelcia.novel.domain + +enum class NovelRankingSearchDays(val value: Int) { + DAY_1(1), + DAY_7(7), + DAY_30(30),; + + companion object { + fun from(days: Int): NovelRankingSearchDays { + return entries.find { it.value == days } + ?: throw IllegalArgumentException("해당하는 일자가 없습니다. days: $days") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/reditus/novelcia/novel/domain/application/NovelQueryService.kt b/src/main/kotlin/com/reditus/novelcia/novel/domain/application/NovelQueryService.kt index bb1eced..2d48cd0 100644 --- a/src/main/kotlin/com/reditus/novelcia/novel/domain/application/NovelQueryService.kt +++ b/src/main/kotlin/com/reditus/novelcia/novel/domain/application/NovelQueryService.kt @@ -6,6 +6,7 @@ import com.reditus.novelcia.novel.domain.port.NovelReader import com.reditus.novelcia.novel.domain.usecase.NovelIdAndScore import com.reditus.novelcia.novel.domain.usecase.NovelScoringUseCase import com.reditus.novelcia.global.util.readOnly +import com.reditus.novelcia.novel.domain.NovelRankingSearchDays import org.springframework.stereotype.Service import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock @@ -30,11 +31,11 @@ class NovelQueryService( * 1-2. 캐시가 존재하지 않으면 스코어링을 조회하여 캐시를 저장하고 반환한다. * 2. `novelIds`를 통해 소설을 조회한다. */ - fun getNovelModelsByRanking(days: Int, size: Int, page: Int): List { + fun getNovelModelsByRanking(days: NovelRankingSearchDays, size: Int, page: Int): List { val localLockCheckNum = lockCheckNum val cache: List? = - novelRankingCacheStore.getNovelIdRankingByPage(days = days, size = size, page = page) + novelRankingCacheStore.getNovelIdRankingByPage(days = days.value, size = size, page = page) if (cache != null) { // 캐시가 존재하면 캐시를 반환 early return return readOnly { @@ -53,7 +54,7 @@ class NovelQueryService( // 같다면, 캐시가 갱신이 안되었고, 현재 쓰레드가 락을 점유하였다. // 같은데, 다른 쓰레드가 캐시를 갱신하였다면, 해당 임계구역을 진입하지 못했다. // Volatile 변수를 사용했기 때문에 CPU 캐시에 저장되지 않고, 메인 메모리에 저장되어 쓰레드간 공유된다. - novelRankingCacheStore.getNovelIdRankingByPage(days = days, size = size, page = page)?.let { + novelRankingCacheStore.getNovelIdRankingByPage(days = days.value, size = size, page = page)?.let { val novelIds = it.map { novelAndScore -> novelAndScore.novelId } return@withLock readOnly { val novels = novelReader.findNovelsByIdsIn(novelIds) @@ -64,12 +65,12 @@ class NovelQueryService( log.warn("NovelScoringUseCase trigger by cache miss (days: $days, lockCheckNum: $lockCheckNum)") - val scoresByOrder = novelScoringUseCase(days = days) // TX BLOCK + val scoresByOrder = novelScoringUseCase(days = days.value) // TX BLOCK if (scoresByOrder.isEmpty()) { // 스코어링 결과가 없으면 early return return@withLock emptyList() } - novelRankingCacheStore.saveNovelIdAndScoresAll(days, scoresByOrder) // 캐시 저장 + novelRankingCacheStore.saveNovelIdAndScoresAll(days.value, scoresByOrder) // 캐시 저장 lockCheckNum += 1 // 캐시 업데이트 했으므로 lockCheckNum 증가 val novelIds = scoresByOrder.map { it.novelId } return@withLock readOnly { // 소설 DB 조회, // TX BLOCK diff --git a/src/main/kotlin/com/reditus/novelcia/novel/interfaces/NovelController.kt b/src/main/kotlin/com/reditus/novelcia/novel/interfaces/NovelController.kt index 26a107e..ae1ed9b 100644 --- a/src/main/kotlin/com/reditus/novelcia/novel/interfaces/NovelController.kt +++ b/src/main/kotlin/com/reditus/novelcia/novel/interfaces/NovelController.kt @@ -4,6 +4,7 @@ import com.reditus.novelcia.common.domain.CursorRequest import com.reditus.novelcia.novel.domain.application.NovelQueryService import com.reditus.novelcia.novel.domain.application.NovelService import com.reditus.novelcia.global.security.LoginUserDetails +import com.reditus.novelcia.novel.domain.NovelRankingSearchDays import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.HttpStatus @@ -29,15 +30,17 @@ class NovelController( return models.map(NovelRes.Meta.Companion::from) } - @Operation(summary = "소설 최근 N일 랭킹 조회") + @Operation(summary = "소설 최근 N일 랭킹 조회", description = "days는 1, 7, 30 중 하나여야 합니다.") @GetMapping("/api/novels/ranking") fun getNovelRanking( @RequestParam days: Int = 1, @RequestParam size: Int = 20, @RequestParam page: Int = 0, ): List { + + val rankingDays = NovelRankingSearchDays.from(days) val models = novelQueryService.getNovelModelsByRanking( - days = days, + days = rankingDays, size = size, page = page, )