feat(home): 크리에이터 랭킹 fallback refresh job을 실행한다

This commit is contained in:
2026-07-10 14:45:10 +09:00
parent 10020b03d6
commit d5ffa56f17
2 changed files with 134 additions and 402 deletions

View File

@@ -35,15 +35,26 @@ class CreatorRankingSnapshotJobService(
fun refreshLastCompletedWeekByScheduledJob() {
withLastCompletedWeekPeriodLock { now, utcRange ->
refreshLastCompletedWeekByScheduledJob(now, utcRange)
refreshLastCompletedWeek(now, utcRange, CreatorRankingSnapshotJobTrigger.SCHEDULED)
}
}
private fun refreshLastCompletedWeekByScheduledJob(
fun refreshLastCompletedWeekByFallback(): Boolean {
var refreshed = false
withLastCompletedWeekPeriodLock { now, utcRange ->
if (fallbackCountReachedLimit(utcRange)) return@withLastCompletedWeekPeriodLock
refreshLastCompletedWeek(now, utcRange, CreatorRankingSnapshotJobTrigger.FALLBACK)
refreshed = true
}
return refreshed
}
private fun refreshLastCompletedWeek(
now: ZonedDateTime,
utcRange: CreatorRankingUtcRange
utcRange: CreatorRankingUtcRange,
trigger: CreatorRankingSnapshotJobTrigger
) {
val job = savePendingJob(utcRange, CreatorRankingSnapshotJobTrigger.SCHEDULED)
val job = savePendingJob(utcRange, trigger)
val jobId = job.id ?: return
markProcessing(jobId)
logJobStatusChanged(job, CreatorRankingSnapshotJobStatus.PROCESSING)
@@ -85,22 +96,25 @@ class CreatorRankingSnapshotJobService(
}!!
}
private fun fallbackCountReachedLimit(utcRange: CreatorRankingUtcRange): Boolean {
return jobPort.countByRankingTypeAndPeriodAndTrigger(
rankingType = CreatorRankingType.WEEKLY,
aggregationStartAtUtc = utcRange.startInclusiveUtc,
aggregationEndAtUtc = utcRange.endExclusiveUtc,
trigger = CreatorRankingSnapshotJobTrigger.FALLBACK
) >= FALLBACK_LIMIT
}
private fun markProcessing(jobId: Long) {
transactionTemplate.executeWithoutResult {
jobPort.markProcessing(jobId, LocalDateTime.now())
}
transactionTemplate.executeWithoutResult { jobPort.markProcessing(jobId, LocalDateTime.now()) }
}
private fun markDone(jobId: Long) {
transactionTemplate.executeWithoutResult {
jobPort.markDone(jobId, LocalDateTime.now())
}
transactionTemplate.executeWithoutResult { jobPort.markDone(jobId, LocalDateTime.now()) }
}
private fun markFailed(jobId: Long, message: String?) {
transactionTemplate.executeWithoutResult {
jobPort.markFailed(jobId, LocalDateTime.now(), message)
}
transactionTemplate.executeWithoutResult { jobPort.markFailed(jobId, LocalDateTime.now(), message) }
}
@Transactional
@@ -128,34 +142,22 @@ class CreatorRankingSnapshotJobService(
aggregationEndAtUtc: LocalDateTime,
statuses: List<CreatorRankingSnapshotJobStatus> = CreatorRankingSnapshotJobStatus.values().toList()
): List<CreatorRankingSnapshotJobRecord> {
return jobPort.findByPeriodAndStatuses(
aggregationStartAtUtc = aggregationStartAtUtc,
aggregationEndAtUtc = aggregationEndAtUtc,
statuses = statuses
)
return jobPort.findByPeriodAndStatuses(aggregationStartAtUtc, aggregationEndAtUtc, statuses)
}
@Transactional
fun retryFailedJob(jobId: Long) {
val job = jobPort.findById(jobId) ?: return
if (job.status != CreatorRankingSnapshotJobStatus.FAILED) return
jobPort.markPending(jobId)
}
fun ensureLastCompletedWeekSnapshotForColdStart() {
withLastCompletedWeekPeriodLock { now, _ ->
transactionTemplate.executeWithoutResult {
refreshService.refreshLastCompletedWeek(now)
}
}
}
private fun withLastCompletedWeekPeriodLock(action: (ZonedDateTime, CreatorRankingUtcRange) -> Unit) {
val now = nowProvider()
val period = periodPolicy.resolveLastCompletedWeek(now)
val utcRange = periodPolicy.toUtcRange(period)
val lockName = "lock:creator-ranking-snapshot-refresh:${utcRange.startInclusiveUtc}:${utcRange.endExclusiveUtc}"
val lockName = "lock:creator-ranking-snapshot-refresh:" +
"${CreatorRankingType.WEEKLY}:${utcRange.startInclusiveUtc}:${utcRange.endExclusiveUtc}"
val lock = redissonClient.getLock(lockName)
try {
@@ -185,4 +187,8 @@ class CreatorRankingSnapshotJobService(
error
)
}
companion object {
private const val FALLBACK_LIMIT = 3L
}
}