콘텐츠 메인 API - 코루틴 적용
This commit is contained in:
parent
0e786f46cb
commit
ce15025c8d
|
@ -55,6 +55,8 @@ dependencies {
|
||||||
implementation("org.json:json:20230227")
|
implementation("org.json:json:20230227")
|
||||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
|
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
|
||||||
|
|
||||||
// firebase admin sdk
|
// firebase admin sdk
|
||||||
implementation("com.google.firebase:firebase-admin:9.2.0")
|
implementation("com.google.firebase:firebase-admin:9.2.0")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kotlinx.coroutines.sync.withPermit
|
||||||
|
|
||||||
|
class SemaphoreManager(private val semaphore: Semaphore) {
|
||||||
|
suspend fun <T> withPermit(block: suspend () -> T): T {
|
||||||
|
return semaphore.withPermit { block() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package kr.co.vividnext.sodalive.configs
|
||||||
|
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kr.co.vividnext.sodalive.common.SemaphoreManager
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class SemaphoreConfig {
|
||||||
|
@Bean
|
||||||
|
fun semaphoreManager(): SemaphoreManager {
|
||||||
|
return SemaphoreManager(Semaphore(4))
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
class AudioContentMainController(private val service: AudioContentMainService) {
|
class AudioContentMainController(private val service: AudioContentMainService) {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
fun getMain(
|
suspend fun getMain(
|
||||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
) = run {
|
) = run {
|
||||||
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package kr.co.vividnext.sodalive.content.main
|
package kr.co.vividnext.sodalive.content.main
|
||||||
|
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kr.co.vividnext.sodalive.common.SemaphoreManager
|
||||||
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
||||||
import kr.co.vividnext.sodalive.content.AudioContentService
|
import kr.co.vividnext.sodalive.content.AudioContentService
|
||||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType
|
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType
|
||||||
|
@ -26,64 +29,100 @@ class AudioContentMainService(
|
||||||
private val orderService: OrderService,
|
private val orderService: OrderService,
|
||||||
private val audioContentThemeRepository: AudioContentThemeQueryRepository,
|
private val audioContentThemeRepository: AudioContentThemeQueryRepository,
|
||||||
|
|
||||||
|
private val semaphoreManager: SemaphoreManager,
|
||||||
|
|
||||||
@Value("\${cloud.aws.cloud-front.host}")
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
private val imageHost: String
|
private val imageHost: String
|
||||||
) {
|
) {
|
||||||
@Cacheable(cacheNames = ["default"], key = "'contentMain:' + #memberId + ':' + #isAdult")
|
suspend fun getMain(memberId: Long, isAdult: Boolean): GetAudioContentMainResponse {
|
||||||
fun getMain(memberId: Long, isAdult: Boolean): GetAudioContentMainResponse {
|
return coroutineScope {
|
||||||
// 2주일 이내에 콘텐츠를 올린 크리에이터 20명 조회
|
// 2주일 이내에 콘텐츠를 올린 크리에이터 20명 조회
|
||||||
val newContentUploadCreatorList = getNewContentUploadCreatorList(memberId = memberId, isAdult = isAdult)
|
val newContentUploadCreatorList = async {
|
||||||
|
semaphoreManager.withPermit {
|
||||||
|
getNewContentUploadCreatorList(memberId = memberId, isAdult = isAdult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val bannerList = getAudioContentMainBannerList(memberId = memberId, isAdult = isAdult)
|
val bannerList = async {
|
||||||
|
semaphoreManager.withPermit {
|
||||||
|
getAudioContentMainBannerList(memberId = memberId, isAdult = isAdult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 구매목록 20개
|
// 구매목록 20개
|
||||||
val orderList = orderService.getAudioContentMainOrderList(
|
val orderList = async {
|
||||||
memberId = memberId,
|
semaphoreManager.withPermit {
|
||||||
limit = 20
|
orderService.getAudioContentMainOrderList(
|
||||||
)
|
memberId = memberId,
|
||||||
|
limit = 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 콘텐츠 테마
|
// 콘텐츠 테마
|
||||||
val themeList = audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
|
val themeList = async {
|
||||||
|
semaphoreManager.withPermit {
|
||||||
|
audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 새 콘텐츠 20개 - 시간 내림차순 정렬
|
// 새 콘텐츠 20개 - 시간 내림차순 정렬
|
||||||
val newContentList = repository.findByTheme(
|
val newContentList = async {
|
||||||
cloudfrontHost = imageHost,
|
semaphoreManager.withPermit {
|
||||||
isAdult = isAdult
|
repository.findByTheme(
|
||||||
)
|
cloudfrontHost = imageHost,
|
||||||
.asSequence()
|
isAdult = isAdult
|
||||||
.filter { !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) }
|
)
|
||||||
.toList()
|
.asSequence()
|
||||||
|
.filter {
|
||||||
|
!blockMemberRepository.isBlocked(
|
||||||
|
blockedMemberId = memberId,
|
||||||
|
memberId = it.creatorId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val curationList = getAudioContentCurationList(memberId = memberId, isAdult = isAdult)
|
val curationList = async {
|
||||||
|
semaphoreManager.withPermit {
|
||||||
|
getAudioContentCurationList(memberId = memberId, isAdult = isAdult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val currentDateTime = LocalDateTime.now()
|
val currentDateTime = LocalDateTime.now()
|
||||||
val startDate = currentDateTime
|
val startDate = currentDateTime
|
||||||
.minusWeeks(1)
|
.minusWeeks(1)
|
||||||
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||||
.withHour(15)
|
.withHour(15)
|
||||||
.withMinute(0)
|
.withMinute(0)
|
||||||
.withSecond(0)
|
.withSecond(0)
|
||||||
val endDate = startDate.plusDays(7)
|
val endDate = startDate.plusDays(7)
|
||||||
|
|
||||||
val contentRankingSortTypeList = audioContentService.getContentRankingSortTypeList()
|
val contentRankingSortTypeList = audioContentService.getContentRankingSortTypeList()
|
||||||
val contentRanking = audioContentService.getAudioContentRanking(
|
val contentRanking = async {
|
||||||
isAdult = isAdult,
|
semaphoreManager.withPermit {
|
||||||
startDate = startDate,
|
audioContentService.getAudioContentRanking(
|
||||||
endDate = endDate,
|
isAdult = isAdult,
|
||||||
offset = 0,
|
startDate = startDate,
|
||||||
limit = 12
|
endDate = endDate,
|
||||||
)
|
offset = 0,
|
||||||
|
limit = 12
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return GetAudioContentMainResponse(
|
GetAudioContentMainResponse(
|
||||||
newContentUploadCreatorList = newContentUploadCreatorList,
|
newContentUploadCreatorList = newContentUploadCreatorList.await(),
|
||||||
bannerList = bannerList,
|
bannerList = bannerList.await(),
|
||||||
orderList = orderList,
|
orderList = orderList.await(),
|
||||||
themeList = themeList,
|
themeList = themeList.await(),
|
||||||
newContentList = newContentList,
|
newContentList = newContentList.await(),
|
||||||
curationList = curationList,
|
curationList = curationList.await(),
|
||||||
contentRankingSortTypeList = contentRankingSortTypeList,
|
contentRankingSortTypeList = contentRankingSortTypeList,
|
||||||
contentRanking = contentRanking
|
contentRanking = contentRanking.await()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getThemeList(member: Member): List<String> {
|
fun getThemeList(member: Member): List<String> {
|
||||||
|
@ -116,6 +155,7 @@ class AudioContentMainService(
|
||||||
return GetNewContentAllResponse(totalCount, items)
|
return GetNewContentAllResponse(totalCount, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = ["default"], key = "'newContentUploadCreatorList:' + #memberId + ':' + #isAdult")
|
||||||
fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> {
|
fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> {
|
||||||
return repository.getNewContentUploadCreatorList(
|
return repository.getNewContentUploadCreatorList(
|
||||||
cloudfrontHost = imageHost,
|
cloudfrontHost = imageHost,
|
||||||
|
@ -126,6 +166,7 @@ class AudioContentMainService(
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = ["default"], key = "'contentMainBannerList:' + #memberId + ':' + #isAdult")
|
||||||
fun getAudioContentMainBannerList(memberId: Long, isAdult: Boolean) =
|
fun getAudioContentMainBannerList(memberId: Long, isAdult: Boolean) =
|
||||||
repository.getAudioContentMainBannerList(isAdult = isAdult)
|
repository.getAudioContentMainBannerList(isAdult = isAdult)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
|
@ -174,6 +215,7 @@ class AudioContentMainService(
|
||||||
}
|
}
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = ["default"], key = "'contentCurationList:' + #memberId + ':' + #isAdult")
|
||||||
fun getAudioContentCurationList(memberId: Long, isAdult: Boolean) =
|
fun getAudioContentCurationList(memberId: Long, isAdult: Boolean) =
|
||||||
repository.getAudioContentCurations(isAdult = isAdult)
|
repository.getAudioContentCurations(isAdult = isAdult)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
|
|
Loading…
Reference in New Issue