후원 랭킹 조회 캐시 적용

This commit is contained in:
2026-01-05 14:46:57 +09:00
parent c494ddcf20
commit 54bfd9987d
5 changed files with 59 additions and 37 deletions

View File

@@ -113,30 +113,6 @@ class ExplorerQueryRepository(
.fetchOne()
}
fun getMemberDonationRankingTotal(creatorId: Long): Int {
val userMember = QMember("user")
val donation = useCan.rewardCan.add(useCan.can).sum()
return queryFactory
.select(userMember.id)
.from(useCanCalculate)
.innerJoin(useCanCalculate.useCan, useCan)
.innerJoin(useCan.member, userMember)
.where(
useCan.isRefund.isFalse
.and(useCanCalculate.recipientCreatorId.eq(creatorId))
.and(
useCan.canUsage.eq(CanUsage.DONATION)
.or(useCan.canUsage.eq(CanUsage.SPIN_ROULETTE))
.or(useCan.canUsage.eq(CanUsage.LIVE))
)
)
.groupBy(useCan.member.id)
.orderBy(donation.desc())
.fetch()
.size
}
fun getMemberDonationRanking(
creatorId: Long,
limit: Long,

View File

@@ -403,6 +403,14 @@ class ExplorerService(
val firstDayOfLastWeek = currentDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(7)
val firstDayOfMonth = currentDate.with(TemporalAdjusters.firstDayOfMonth())
val donationMemberTotal = donationRankingService.getMemberDonationRankingTotal(creatorId)
val donationRanking = donationRankingService.getMemberDonationRanking(
creatorId = creatorId,
offset = pageable.offset,
limit = pageable.pageSize.toLong(),
withDonationCan = creatorId == member.id!!
)
return GetDonationAllResponse(
accumulatedCansToday = if (creatorId == member.id!!) {
queryRepository.getDonationCoinsDateRange(
@@ -436,13 +444,8 @@ class ExplorerService(
} else {
false
},
totalCount = queryRepository.getMemberDonationRankingTotal(creatorId),
userDonationRanking = queryRepository.getMemberDonationRanking(
creatorId,
offset = pageable.offset,
limit = pageable.pageSize.toLong(),
withDonationCan = creatorId == member.id!!
)
totalCount = donationMemberTotal,
userDonationRanking = donationRanking
)
}

View File

@@ -13,6 +13,7 @@ import org.springframework.stereotype.Repository
class CreatorDonationRankingQueryRepository(private val queryFactory: JPAQueryFactory) {
fun getMemberDonationRanking(
creatorId: Long,
offset: Long,
limit: Long
): List<DonationRankingProjection> {
val donationCan = useCan.rewardCan.add(useCan.can).sum()
@@ -38,12 +39,33 @@ class CreatorDonationRankingQueryRepository(private val queryFactory: JPAQueryFa
.or(useCan.canUsage.eq(CanUsage.LIVE))
)
)
.offset(0)
.offset(offset)
.limit(limit)
.groupBy(member.id)
.orderBy(donationCan.desc(), member.id.desc())
.fetch()
}
fun getMemberDonationRankingTotal(creatorId: Long): Int {
return queryFactory
.select(member.id)
.from(useCanCalculate)
.innerJoin(useCanCalculate.useCan, useCan)
.innerJoin(useCan.member, member)
.where(
useCan.member.isActive.isTrue
.and(useCan.isRefund.isFalse)
.and(useCanCalculate.recipientCreatorId.eq(creatorId))
.and(
useCan.canUsage.eq(CanUsage.DONATION)
.or(useCan.canUsage.eq(CanUsage.SPIN_ROULETTE))
.or(useCan.canUsage.eq(CanUsage.LIVE))
)
)
.groupBy(member.id)
.fetch()
.size
}
}
data class DonationRankingProjection @QueryProjection constructor(

View File

@@ -20,18 +20,41 @@ class CreatorDonationRankingService(
@Value("\${cloud.aws.cloud-front.host}")
private val imageHost: String
) {
fun getMemberDonationRankingTotal(creatorId: Long): Int {
val cacheKey = "creator_donation_ranking_member_total_v2:$creatorId"
val cachedTotal = redisTemplate.opsForValue().get(cacheKey) as? Int
if (cachedTotal != null) {
return cachedTotal
}
val total = repository.getMemberDonationRankingTotal(creatorId)
val now = LocalDateTime.now()
val nextMonday = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).with(LocalTime.MIN)
val secondsUntilNextMonday = ChronoUnit.SECONDS.between(now, nextMonday)
redisTemplate.opsForValue().set(
cacheKey,
total,
Duration.ofSeconds(secondsUntilNextMonday)
)
return total
}
fun getMemberDonationRanking(
creatorId: Long,
limit: Long,
offset: Long = 0,
limit: Long = 10,
withDonationCan: Boolean
): List<MemberDonationRankingResponse> {
val cacheKey = "creator_donation_ranking_v2:$creatorId:$limit:$withDonationCan"
val cacheKey = "creator_donation_ranking_v2:$creatorId:$offset:$limit:$withDonationCan"
val cachedData = redisTemplate.opsForValue().get(cacheKey) as? MemberDonationRankingListResponse
if (cachedData != null) {
return cachedData.rankings
}
val memberDonationRanking = repository.getMemberDonationRanking(creatorId, limit)
val memberDonationRanking = repository.getMemberDonationRanking(creatorId, offset, limit)
val result = memberDonationRanking.map {
MemberDonationRankingResponse(

View File

@@ -888,9 +888,7 @@ class LiveRoomService(
3,
withDonationCan = false
)
.asSequence()
.map { it.userId }
.toList()
} else {
listOf()
}