feat(gift): 선물 배송 스케줄러를 추가한다
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
package kr.co.vividnext.sodalive.v2.gift.adapter.out.scheduler
|
||||
|
||||
import kr.co.vividnext.sodalive.can.payment.CanPaymentService
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDeliveryRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftPushService
|
||||
import kr.co.vividnext.sodalive.v2.gift.domain.GiftStatus
|
||||
import org.redisson.api.RedissonClient
|
||||
import org.springframework.scheduling.annotation.Scheduled
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.LocalDateTime
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Component
|
||||
class GiftScheduler(
|
||||
private val giftRepository: GiftRepository,
|
||||
private val giftDeliveryRepository: GiftDeliveryRepository,
|
||||
private val canPaymentService: CanPaymentService,
|
||||
private val giftPushService: GiftPushService,
|
||||
private val redissonClient: RedissonClient
|
||||
) {
|
||||
@Scheduled(cron = "0 0 * * * *", zone = "Asia/Seoul")
|
||||
@Transactional
|
||||
fun runExpiredTrackingRegistrationGiftCancellation() {
|
||||
val lock = redissonClient.getLock(EXPIRED_TRACKING_REGISTRATION_GIFTS_LOCK_KEY)
|
||||
|
||||
try {
|
||||
if (lock.tryLock(0, -1, TimeUnit.SECONDS)) {
|
||||
cancelExpiredTrackingRegistrationGifts(LocalDateTime.now())
|
||||
}
|
||||
} finally {
|
||||
if (lock.isHeldByCurrentThread) {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun cancelExpiredTrackingRegistrationGifts(now: LocalDateTime): Int {
|
||||
val expiredGifts = giftRepository.findReceivedGiftsWithTrackingDeadlineBefore(now)
|
||||
expiredGifts.forEach { gift ->
|
||||
gift.status = GiftStatus.CANCELED
|
||||
requireNotNull(giftDeliveryRepository.findByGiftId(requireNotNull(gift.id))).canceledAt = now
|
||||
canPaymentService.refundGiftCan(gift.senderMemberId, gift.canUsageId)
|
||||
giftPushService.sendAutoCanceledToSender(gift.applicationNo, gift.senderMemberId)
|
||||
}
|
||||
|
||||
return expiredGifts.size
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun markExpiredRecipientAddressGiftsUndeliverable(now: LocalDateTime): Int {
|
||||
val expiredGifts = giftRepository.findTrackingRegisteredGiftsWithRecipientAddressDeadlineBefore(now)
|
||||
expiredGifts.forEach { gift ->
|
||||
gift.status = GiftStatus.UNDELIVERABLE
|
||||
val delivery = requireNotNull(giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)))
|
||||
delivery.undeliverableAt = now
|
||||
delivery.undeliverableReason = EXPIRED_RECIPIENT_ADDRESS_REASON
|
||||
}
|
||||
|
||||
return expiredGifts.size
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun sendDeadlineReminderGifts(now: LocalDateTime): Int {
|
||||
val reminderUntil = now.plusHours(DEADLINE_REMINDER_HOURS)
|
||||
val trackingReminderCount = sendTrackingDeadlineReminders(now, reminderUntil)
|
||||
val recipientAddressReminderCount = sendRecipientAddressDeadlineReminders(now, reminderUntil)
|
||||
|
||||
return trackingReminderCount + recipientAddressReminderCount
|
||||
}
|
||||
|
||||
private fun sendTrackingDeadlineReminders(now: LocalDateTime, reminderUntil: LocalDateTime): Int {
|
||||
val gifts = giftRepository.findReceivedGiftsWithTrackingDeadlineReminderDue(now, reminderUntil)
|
||||
gifts.forEach { gift ->
|
||||
val delivery = requireNotNull(giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)))
|
||||
delivery.trackingDeadlineReminderSentAt = now
|
||||
giftPushService.sendTrackingDeadlineReminder(gift.applicationNo, gift.senderMemberId)
|
||||
}
|
||||
|
||||
return gifts.size
|
||||
}
|
||||
|
||||
private fun sendRecipientAddressDeadlineReminders(now: LocalDateTime, reminderUntil: LocalDateTime): Int {
|
||||
val gifts = giftRepository.findGiftsWithRecipientAddressDeadlineReminderDue(now, reminderUntil)
|
||||
gifts.forEach { gift ->
|
||||
val delivery = requireNotNull(giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)))
|
||||
delivery.recipientAddressDeadlineReminderSentAt = now
|
||||
giftPushService.sendRecipientAddressDeadlineReminder(gift.applicationNo, gift.recipientMemberId)
|
||||
}
|
||||
|
||||
return gifts.size
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DEADLINE_REMINDER_HOURS = 24L
|
||||
const val EXPIRED_TRACKING_REGISTRATION_GIFTS_LOCK_KEY = "lock:gift-expired-tracking-registration-cancellation"
|
||||
const val EXPIRED_RECIPIENT_ADDRESS_REASON = "배송지 미입력 기한 초과"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user