From af352256e95de640ff54ec4149b686042c9a6797 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 22 May 2025 12:25:17 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=EC=BD=94=EB=A3=A8=ED=8B=B4=20?= =?UTF-8?q?=EB=82=B4=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20=EA=B0=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=95=88=20=EB=90=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20-=20=EA=B0=81=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=EC=9D=84=20TransactionTemplate=20?= =?UTF-8?q?=EB=B8=94=EB=A1=9D=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=BB=A4=EB=B0=8B=20=EC=8B=9C=EC=A0=90=20?= =?UTF-8?q?=EB=AA=85=ED=99=95=ED=99=94=20-=20=EB=91=90=20=EB=B2=88?= =?UTF-8?q?=EC=A7=B8=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=EC=97=90?= =?UTF-8?q?=EC=84=9C=20entityManager.clear()=20=ED=98=B8=EC=B6=9C=EB=A1=9C?= =?UTF-8?q?=201=EC=B0=A8=20=EC=BA=90=EC=8B=9C=20=EB=AC=B4=EC=8B=9C=20-=20C?= =?UTF-8?q?oroutineExceptionHandler=20=EC=B6=94=EA=B0=80=EB=A1=9C=20?= =?UTF-8?q?=EB=B9=84=EB=8F=99=EA=B8=B0=20=EC=98=88=EC=99=B8=20=EB=A1=9C?= =?UTF-8?q?=EA=B9=85=20=EC=B2=98=EB=A6=AC=20-=20@PreDestroy=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=A1=9C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20=EC=8B=9C=20CoroutineScope=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/useraction/UserActionService.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt index 1025369..cd2bf7e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt @@ -1,7 +1,9 @@ package kr.co.vividnext.sodalive.useraction +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kr.co.vividnext.sodalive.content.order.OrderRepository import kr.co.vividnext.sodalive.fcm.FcmService @@ -14,6 +16,8 @@ import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import org.springframework.transaction.support.TransactionTemplate import java.time.LocalDateTime +import javax.annotation.PreDestroy +import javax.persistence.EntityManager @Service class UserActionService( @@ -24,10 +28,15 @@ class UserActionService( private val memberPointRepository: MemberPointRepository, private val transactionTemplate: TransactionTemplate, - private val fcmService: FcmService + private val fcmService: FcmService, + private val entityManager: EntityManager ) { - private val coroutineScope = CoroutineScope(Dispatchers.IO) + private val coroutineScope = CoroutineScope( + Dispatchers.IO + CoroutineExceptionHandler { _, e -> + logger.error("포인트 지급 또는 알림 실패: ${e.message}") + } + ) fun recordAction( memberId: Long, @@ -53,6 +62,7 @@ class UserActionService( if (isAuth) { try { transactionTemplate.execute { + entityManager.clear() val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now) if (policy != null) { val policyType = policy.policyType @@ -146,6 +156,11 @@ class UserActionService( } } + @PreDestroy + fun onDestroy() { + coroutineScope.cancel("UserActionService 종료") + } + companion object { private val logger = LoggerFactory.getLogger(UserActionService::class.java) } -- 2.40.1 From dc130538254eb7db543224c14d65d984a4359daa Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 22 May 2025 13:01:39 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EA=B5=AC=EB=A7=A4=ED=95=98=EC=A7=80?= =?UTF-8?q?=20=EC=95=8A=EC=9D=80=20=EC=BD=98=ED=85=90=EC=B8=A0=EC=97=90=20?= =?UTF-8?q?=EB=8C=93=EA=B8=80=EC=9D=84=20=EC=8D=A8=EB=8F=84=20ORDER=5FCONT?= =?UTF-8?q?ENT=5FCOMMENT=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=EA=B0=80=20?= =?UTF-8?q?=EC=9E=88=EC=9C=BC=EB=A9=B4=20=EC=9C=A0=EC=A0=80=20=ED=96=89?= =?UTF-8?q?=EB=8F=99=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EC=97=90=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/useraction/UserActionService.kt | 211 ++++++++++-------- 1 file changed, 122 insertions(+), 89 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt index cd2bf7e..f26415d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import kr.co.vividnext.sodalive.content.order.OrderRepository import kr.co.vividnext.sodalive.fcm.FcmService import kr.co.vividnext.sodalive.point.MemberPoint @@ -48,109 +49,141 @@ class UserActionService( ) { coroutineScope.launch { val now = LocalDateTime.now() - transactionTemplate.execute { - repository.save( - UserActionLog( + val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now) + if (policy != null) { + val policyType = policy.policyType + val todayAt15 = now.toLocalDate().atTime(15, 0) + val policyTypeDailyStartDate = if (now.toLocalTime().isBefore(todayAt15.toLocalTime())) { + now.toLocalDate().minusDays(1).atTime(15, 0) + } else { + todayAt15 + } + + val isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate = + policyType == PolicyType.DAILY && policyTypeDailyStartDate >= policy.startDate + val order = if (contentId != null) { + orderRepository.findByMemberIdAndContentId( memberId = memberId, - actionType = actionType, - contentCommentId = contentCommentId + contentId = contentId, + createdAt = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { + policyTypeDailyStartDate + } else { + policy.startDate + } ) - ) - repository.flush() + } else { + null + } + if (actionType == ActionType.ORDER_CONTENT_COMMENT && order == null) return@launch } - if (isAuth) { - try { - transactionTemplate.execute { - entityManager.clear() - val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now) - if (policy != null) { - val policyType = policy.policyType - val todayAt15 = now.toLocalDate().atTime(15, 0) - val policyTypeDailyStartDate = if (now.toLocalTime().isBefore(todayAt15.toLocalTime())) { - now.toLocalDate().minusDays(1).atTime(15, 0) - } else { - todayAt15 - } + withContext(Dispatchers.IO) { + transactionTemplate.execute { + repository.save( + UserActionLog( + memberId = memberId, + actionType = actionType, + contentCommentId = contentCommentId + ) + ) + repository.flush() + } + } - val isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate = - policyType == PolicyType.DAILY && policyTypeDailyStartDate >= policy.startDate - val order = if (contentId != null) { - orderRepository.findByMemberIdAndContentId( + withContext(Dispatchers.IO) { + if (isAuth) { + try { + transactionTemplate.execute { + entityManager.clear() + if (policy != null) { + val policyType = policy.policyType + val todayAt15 = now.toLocalDate().atTime(15, 0) + val policyTypeDailyStartDate = + if (now.toLocalTime().isBefore(todayAt15.toLocalTime())) { + now.toLocalDate().minusDays(1).atTime(15, 0) + } else { + todayAt15 + } + + val isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate = + policyType == PolicyType.DAILY && policyTypeDailyStartDate >= policy.startDate + val order = if (contentId != null) { + orderRepository.findByMemberIdAndContentId( + memberId = memberId, + contentId = contentId, + createdAt = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { + policyTypeDailyStartDate + } else { + policy.startDate + } + ) + } else { + null + } + if (actionType == ActionType.ORDER_CONTENT_COMMENT && order == null) return@execute + + val actionCount = repository.countByMemberIdAndActionTypeAndCreatedAtBetween( memberId = memberId, - contentId = contentId, - createdAt = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { + actionType = actionType, + startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { policyTypeDailyStartDate } else { policy.startDate + }, + endDate = policy.endDate ?: now + ) + if (actionCount < policy.threshold) return@execute + + val grantedCount = grantLogRepository.countByMemberIdAndPolicyIdAndStartDate( + memberId, + policy.id!!, + startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { + policyTypeDailyStartDate + } else { + policy.startDate + }, + orderId = order?.id + ) + if (grantedCount >= policy.availableCount) return@execute + + val point = if (actionType == ActionType.ORDER_CONTENT_COMMENT && order != null) { + order.can + } else { + policy.pointAmount + } + + if (point > 0) { + grantLogRepository.save( + PointGrantLog( + memberId = memberId, + point = point, + actionType = actionType, + policyId = policy.id!!, + orderId = order?.id + ) + ) + + memberPointRepository.save( + MemberPoint( + memberId = memberId, + point = point, + actionType = actionType, + expiresAt = now.plusDays(3) + ) + ) + + if (pushTokenList.isNotEmpty()) { + fcmService.sendPointGranted( + pushTokenList, + point + ) } - ) - } else { - null - } - if (actionType == ActionType.ORDER_CONTENT_COMMENT && order == null) return@execute - - val actionCount = repository.countByMemberIdAndActionTypeAndCreatedAtBetween( - memberId = memberId, - actionType = actionType, - startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { - policyTypeDailyStartDate - } else { - policy.startDate - }, - endDate = policy.endDate ?: now - ) - if (actionCount < policy.threshold) return@execute - - val grantedCount = grantLogRepository.countByMemberIdAndPolicyIdAndStartDate( - memberId, - policy.id!!, - startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) { - policyTypeDailyStartDate - } else { - policy.startDate - }, - orderId = order?.id - ) - if (grantedCount >= policy.availableCount) return@execute - - val point = if (actionType == ActionType.ORDER_CONTENT_COMMENT && order != null) { - order.can - } else { - policy.pointAmount - } - - if (point > 0) { - grantLogRepository.save( - PointGrantLog( - memberId = memberId, - point = point, - actionType = actionType, - policyId = policy.id!!, - orderId = order?.id - ) - ) - - memberPointRepository.save( - MemberPoint( - memberId = memberId, - point = point, - actionType = actionType, - expiresAt = now.plusDays(3) - ) - ) - - if (pushTokenList.isNotEmpty()) { - fcmService.sendPointGranted( - pushTokenList, - point - ) } } } + } catch (e: Exception) { + logger.warn("포인트 지급 또는 알림 실패: ${e.message}") } - } catch (e: Exception) { - logger.warn("포인트 지급 또는 알림 실패: ${e.message}") } } } -- 2.40.1 From e67b79871472b2497780b74410a3a8a88b1ea76a Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 22 May 2025 13:19:52 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20actionCount=20=EB=A5=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=A0=20=EB=95=8C=20endDate=EA=B0=80=20=EB=A7=88?= =?UTF-8?q?=EC=A7=80=EB=A7=89=20action=20=EC=A0=80=EC=9E=A5=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84=EC=9D=98=20=EC=8B=9C=EA=B0=84=EC=9D=B4=20=EC=B8=A1?= =?UTF-8?q?=EC=A0=95=EB=90=A0=20=EC=88=98=EB=8F=84=20=EC=9E=88=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20LocalDateTime.now()=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/useraction/UserActionService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt index f26415d..8dd1ab5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt @@ -130,7 +130,7 @@ class UserActionService( } else { policy.startDate }, - endDate = policy.endDate ?: now + endDate = policy.endDate ?: LocalDateTime.now() ) if (actionCount < policy.threshold) return@execute -- 2.40.1