Skip to content

Commit d820139

Browse files
committed
✨ feat(scheduler) : userChallenge 관련 배치 처리 구현 완료
1 parent 904a95a commit d820139

File tree

6 files changed

+90
-27
lines changed

6 files changed

+90
-27
lines changed
Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
package com.app.server.core.scheduler
22

3+
import com.app.server.user_challenge.application.service.UserChallengeCommandService
4+
import kotlinx.coroutines.CoroutineScope
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.SupervisorJob
7+
import kotlinx.coroutines.launch
38
import org.springframework.context.annotation.Configuration
9+
import org.springframework.scheduling.annotation.Scheduled
10+
import java.time.LocalDate
411

512
@Configuration
6-
class UserChallengeScheduler {
7-
/**
8-
* TODO: 챌린지 종료 일자보다 오늘 일자가 더 크다면, 챌린지 상태를 Pending으로 변경한다.
9-
* 이건 즉 마지막 날짜에 인증하지 못한 챌린지들이 리포트를 발급받을 수 있게 한다.
10-
*/
13+
class UserChallengeScheduler (
14+
private val userChallengeCommandService: UserChallengeCommandService
15+
){
1116

12-
// TODO : Pending 상태인 챌린지들도 시간 보고 COMPLETED 상태로 변경해줘야 함.
13-
// TODO 배치로 WAIT 상태인 챌린지들을 COMPLETED로 변경하는 작업이 필요하다.
14-
// TODO: WAIT 상태인 챌린지들은 endDate.plusDays(1)보다 .isAfter하면 COMPLETED로 상태 변경 배치 작업 필요
17+
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
18+
19+
@Scheduled(cron = "0 0 0 * * ?")
20+
fun updateChallengeStatusToPending() {
21+
scope.launch {
22+
userChallengeCommandService.batchUpdateChallengeStatusFromRunningToPending(LocalDate.now())
23+
}
24+
}
25+
26+
@Scheduled(cron = "0 0 0 * * ?")
27+
fun updateChallengeStatusFromPendingToCompleted() {
28+
scope.launch {
29+
userChallengeCommandService.batchUpdateChallengeStatusFromPendingToCompleted(LocalDate.now())
30+
}
31+
}
32+
33+
@Scheduled(cron = "0 0 0 * * ?")
34+
fun updateChallengeStatusFromWaitingToCompleted() {
35+
scope.launch {
36+
userChallengeCommandService.batchUpdateChallengeStatusFromWaitingToCompleted(LocalDate.now())
37+
}
38+
}
1539

1640
}

server/src/main/kotlin/com/app/server/user_challenge/application/repository/UserChallengeRepository.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ interface UserChallengeRepository : JpaRepository<UserChallenge, Long> {
3939
"AND uc.deletedAt IS NULL")
4040
fun findAllByUserId(userId: Long): List<UserChallenge>
4141

42+
@Query("SELECT uc FROM UserChallenge uc " +
43+
"WHERE uc.status = :status " +
44+
"AND uc.deletedAt IS NULL")
45+
fun findAllByStatus(status: EUserChallengeStatus): Optional<List<UserChallenge>>
46+
4247
}

server/src/main/kotlin/com/app/server/user_challenge/application/service/UserChallengeCommandService.kt

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,29 @@ import com.app.server.challenge.ui.usecase.dto.request.ChallengeParticipantDto
55
import com.app.server.challenge_certification.application.dto.CertificationDataDto
66
import com.app.server.challenge_certification.application.service.constant.EConsecutiveState
77
import com.app.server.challenge_certification.ui.dto.UserChallengeIceRequestDto
8-
import com.app.server.user_challenge.ui.usecase.UsingIceUseCase
98
import com.app.server.common.exception.InternalServerErrorException
109
import com.app.server.user_challenge.application.dto.CreateUserChallengeDto
1110
import com.app.server.user_challenge.application.dto.ReceiveReportResponseDto
12-
import com.app.server.user_challenge.ui.usecase.ParticipantChallengeUseCase
1311
import com.app.server.user_challenge.domain.enums.EUserChallengeCertificationStatus
1412
import com.app.server.user_challenge.domain.enums.EUserChallengeStatus
13+
import com.app.server.user_challenge.domain.event.ReportCreatedEvent
14+
import com.app.server.user_challenge.domain.event.SavedTodayUserChallengeCertificationEvent
1515
import com.app.server.user_challenge.domain.exception.UserChallengeException
1616
import com.app.server.user_challenge.domain.model.UserChallenge
1717
import com.app.server.user_challenge.domain.model.UserChallengeHistory
1818
import com.app.server.user_challenge.enums.EUserChallengeParticipantState
1919
import com.app.server.user_challenge.enums.EUserReportResultCode
20-
import com.app.server.user_challenge.domain.event.ReportCreatedEvent
21-
import com.app.server.user_challenge.domain.event.SavedTodayUserChallengeCertificationEvent
2220
import com.app.server.user_challenge.infra.ReportInfraService
2321
import com.app.server.user_challenge.ui.dto.SendToReportServerRequestDto
22+
import com.app.server.user_challenge.ui.usecase.ParticipantChallengeUseCase
23+
import com.app.server.user_challenge.ui.usecase.UsingIceUseCase
2424
import org.springframework.context.ApplicationEventPublisher
2525
import org.springframework.stereotype.Service
26+
import org.springframework.transaction.annotation.Transactional
2627
import java.time.LocalDate
2728

2829
@Service
30+
@Transactional
2931
class UserChallengeCommandService(
3032
private val userChallengeService: UserChallengeService,
3133
private val challengeService: ChallengeService,
@@ -103,7 +105,7 @@ class UserChallengeCommandService(
103105
userChallenge.validateIncreaseIceCount()
104106

105107
// 챌린지 종료 여부 확인
106-
if (userChallenge.checkIsDone(certificationDto.certificationDate)) {
108+
if (userChallenge.checkIsNotRunning(certificationDto.certificationDate)) {
107109
makeReport(userChallenge)
108110
}
109111

@@ -146,7 +148,7 @@ class UserChallengeCommandService(
146148
when (report.status) {
147149
EUserReportResultCode.RECEIVE_REPORT_SUCCESS -> {
148150
userChallenge.updateReportMessage(report.message)
149-
updateUserChallengeStatusToPending(userChallenge)
151+
userChallenge.updateStatus(EUserChallengeStatus.PENDING)
150152
}
151153

152154
EUserReportResultCode.RECEIVE_REPORT_FAILED -> {
@@ -165,10 +167,6 @@ class UserChallengeCommandService(
165167
}
166168
}
167169

168-
private fun updateUserChallengeStatusToPending(userChallenge: UserChallenge) {
169-
userChallenge.updateStatus(EUserChallengeStatus.PENDING)
170-
}
171-
172170
override fun processAfterCertificateIce(
173171
iceDto: UserChallengeIceRequestDto,
174172
certificationDate: LocalDate
@@ -304,4 +302,32 @@ class UserChallengeCommandService(
304302
// UserChallenge와 연결된 모든 히스토리가 함께 저장됨
305303
userChallengeService.save(userChallenge)
306304
}
305+
306+
suspend fun batchUpdateChallengeStatusFromRunningToPending(validateToday: LocalDate) {
307+
val runningUserChallengeList : List<UserChallenge> = userChallengeService.findAllByStatus(EUserChallengeStatus.RUNNING)
308+
309+
runningUserChallengeList.forEach { userChallenge ->
310+
if (userChallenge.checkIsNotRunning(validateToday)) {
311+
makeReport(userChallenge)
312+
}
313+
}
314+
}
315+
316+
suspend fun batchUpdateChallengeStatusFromPendingToCompleted(validateToday: LocalDate) {
317+
val pendingUserChallengeList : List<UserChallenge> = userChallengeService.findAllByStatus(EUserChallengeStatus.PENDING)
318+
pendingUserChallengeList.forEach { userChallenge ->
319+
if (userChallenge.checkIsCompleted(validateToday)) {
320+
userChallenge.updateStatus(EUserChallengeStatus.COMPLETED)
321+
}
322+
}
323+
}
324+
325+
suspend fun batchUpdateChallengeStatusFromWaitingToCompleted(validateToday: LocalDate) {
326+
val waitingUserChallengeList : List<UserChallenge> = userChallengeService.findAllByStatus(EUserChallengeStatus.WAITING)
327+
waitingUserChallengeList.forEach { userChallenge ->
328+
if (userChallenge.checkIsCompleted(validateToday)) {
329+
userChallenge.updateStatus(EUserChallengeStatus.COMPLETED)
330+
}
331+
}
332+
}
307333
}

server/src/main/kotlin/com/app/server/user_challenge/application/service/UserChallengeService.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.app.server.common.exception.NotFoundException
55
import com.app.server.user_challenge.application.repository.UserChallengeRepository
66
import com.app.server.user_challenge.domain.enums.EUserChallengeCertificationStatus
77
import com.app.server.user_challenge.domain.enums.EUserChallengeStatus
8+
import com.app.server.user_challenge.domain.exception.UserChallengeException
89
import com.app.server.user_challenge.domain.model.UserChallenge
910
import com.app.server.user_challenge.domain.model.UserChallengeHistory
1011
import org.springframework.stereotype.Service
@@ -46,22 +47,21 @@ class UserChallengeService (
4647
challengeId = challengeId
4748
)
4849

49-
fun findHistoryByUserChallenge(userChallengeId: Long): List<UserChallengeHistory> {
50-
return findById(userChallengeId).getUserChallengeHistories()
51-
}
52-
5350
fun deleteAll() {
5451
userChallengeRepository.deleteAll()
5552
}
5653

57-
fun flush(){
58-
userChallengeRepository.flush()
59-
}
60-
6154
fun isCertificatedWhen(userChallengeId : Long, todayDate : LocalDate) : EUserChallengeCertificationStatus {
6255
return findById(userChallengeId).isCertificatedToday(todayDate)
6356
}
6457
fun getUserChallengeImageUrl(userChallengeId : Long, imageDate : LocalDate): String {
6558
return findById(userChallengeId).getUserChallengeImageUrl(imageDate)
6659
}
60+
61+
fun findAllByStatus(status: EUserChallengeStatus): List<UserChallenge> {
62+
return userChallengeRepository.findAllByStatus(status)
63+
.orElseThrow{
64+
NotFoundException(UserChallengeException.NOT_FOUND_THIS_STATUS)
65+
}
66+
}
6767
}

server/src/main/kotlin/com/app/server/user_challenge/domain/exception/UserChallengeException.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ enum class UserChallengeException(
2020
ERROR_IN_CERTIFICATED_SERVER("UCH011", "챌린지 인증 서버 오류입니다."),
2121
CANNOT_MAKE_REPORT("UCH0012", "리포트를 만들 수 없습니다."),
2222
ERROR_IN_REPORT_SERVER("UCH0013", "리포트 서버 오류입니다."),
23+
NOT_FOUND_THIS_STATUS("UCH0014", "해당 상태의 챌린지가 존재하지 않습니다."),
2324
;
2425

2526
}

server/src/main/kotlin/com/app/server/user_challenge/domain/model/UserChallenge.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class UserChallenge(
194194
return userChallengeHistories.filter { it.date.isBefore(todayDate.plusDays(1)) }
195195
}
196196

197-
fun checkIsDone(todayDate: LocalDate): Boolean {
197+
fun checkIsNotRunning(todayDate: LocalDate): Boolean {
198198
// status가 running인데, 오늘 날짜와 챌린지 종료 날짜가 같은 상황에서 인증이 완료되었거나, 챌린지 종료 날짜가 지난 경우
199199
val endDate = this.createdAt!!.toLocalDate().plusDays(participantDays - 1L)
200200

@@ -206,6 +206,13 @@ class UserChallenge(
206206
)
207207
}
208208

209+
fun checkIsCompleted(todayDate: LocalDate): Boolean {
210+
// 챌린지 종료 일보다 현재 날짜가 이틀 더 지났을 때
211+
val endDate = this.createdAt!!.toLocalDate().plusDays(participantDays - 1L)
212+
213+
return todayDate.isAfter(endDate.plusDays(1))
214+
}
215+
209216
fun getUserChallengeImageUrl(imageDate: LocalDate): String {
210217
return this.userChallengeHistories.find { it.date.isEqual(imageDate) }!!.certificatedImageUrl!!
211218
}

0 commit comments

Comments
 (0)