feat(ranking): 스냅샷 job 관리 기능을 추가한다

This commit is contained in:
2026-06-09 11:49:50 +09:00
parent 929c056ebf
commit 2db37edb5b
5 changed files with 216 additions and 0 deletions

View File

@@ -59,6 +59,18 @@ class DefaultCreatorRankingSnapshotJobRepository(
return job.toRecord()
}
@Transactional
override fun markPending(jobId: Long): CreatorRankingSnapshotJobRecord? {
val job = repository.findByIdForUpdate(jobId) ?: return null
if (job.status != CreatorRankingSnapshotJobStatus.FAILED) return job.toRecord()
job.status = CreatorRankingSnapshotJobStatus.PENDING
job.lastError = null
job.processingStartedAt = null
job.processedAt = null
return job.toRecord()
}
private fun CreatorRankingSnapshotJobRecord.toEntity(): CreatorRankingSnapshotJob {
return CreatorRankingSnapshotJob(
aggregationStartAtUtc = aggregationStartAtUtc,

View File

@@ -6,10 +6,12 @@ import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotJobRec
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotJobStatus
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotJobTrigger
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
import java.time.ZonedDateTime
@Service
@Transactional(readOnly = true)
class CreatorRankingSnapshotJobService(
private val refreshService: CreatorRankingSnapshotRefreshService,
private val jobPort: CreatorRankingSnapshotJobPort,
@@ -17,6 +19,7 @@ class CreatorRankingSnapshotJobService(
) {
private val periodPolicy = CreatorRankingPeriodPolicy()
@Transactional
fun refreshLastCompletedWeekByScheduledJob() {
val now = nowProvider()
val period = periodPolicy.resolveLastCompletedWeek(now)
@@ -42,4 +45,42 @@ class CreatorRankingSnapshotJobService(
throw ex
}
}
@Transactional
fun createManualJob(
aggregationStartAtUtc: LocalDateTime,
aggregationEndAtUtc: LocalDateTime
): CreatorRankingSnapshotJobRecord {
return jobPort.save(
CreatorRankingSnapshotJobRecord(
aggregationStartAtUtc = aggregationStartAtUtc,
aggregationEndAtUtc = aggregationEndAtUtc,
trigger = CreatorRankingSnapshotJobTrigger.MANUAL,
status = CreatorRankingSnapshotJobStatus.PENDING,
lastError = null,
processingStartedAt = null,
processedAt = null
)
)
}
fun findJobs(
aggregationStartAtUtc: LocalDateTime,
aggregationEndAtUtc: LocalDateTime,
statuses: List<CreatorRankingSnapshotJobStatus> = CreatorRankingSnapshotJobStatus.values().toList()
): List<CreatorRankingSnapshotJobRecord> {
return jobPort.findByPeriodAndStatuses(
aggregationStartAtUtc = aggregationStartAtUtc,
aggregationEndAtUtc = aggregationEndAtUtc,
statuses = statuses
)
}
@Transactional
fun retryFailedJob(jobId: Long) {
val job = jobPort.findById(jobId) ?: return
if (job.status != CreatorRankingSnapshotJobStatus.FAILED) return
jobPort.markPending(jobId)
}
}

View File

@@ -18,6 +18,8 @@ interface CreatorRankingSnapshotJobPort {
fun markDone(jobId: Long, processedAt: LocalDateTime): CreatorRankingSnapshotJobRecord?
fun markFailed(jobId: Long, processedAt: LocalDateTime, lastError: String?): CreatorRankingSnapshotJobRecord?
fun markPending(jobId: Long): CreatorRankingSnapshotJobRecord?
}
enum class CreatorRankingSnapshotJobStatus {