diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobService.kt index 8f0b3b9e..60da8940 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobService.kt @@ -18,6 +18,7 @@ import org.springframework.context.ApplicationEventPublisher import org.springframework.dao.DataIntegrityViolationException import org.springframework.stereotype.Service import org.springframework.transaction.PlatformTransactionManager +import org.springframework.transaction.TransactionDefinition import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.support.TransactionSynchronization import org.springframework.transaction.support.TransactionSynchronizationManager @@ -37,7 +38,11 @@ class ChargeEventJobService( private val applicationEventPublisher: ApplicationEventPublisher? = null, transactionManager: PlatformTransactionManager? = null ) { - private val transactionTemplate = transactionManager?.let { TransactionTemplate(it) } + private val transactionTemplate = transactionManager?.let { + TransactionTemplate(it).also { template -> + template.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRES_NEW + } + } @Transactional fun createAndProcessImmediate(sourceChargeId: Long, memberId: Long): ChargeEventJob? { diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobServiceTest.kt index fa954182..8f581f6a 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/can/charge/event/ChargeEventJobServiceTest.kt @@ -10,6 +10,10 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test import org.mockito.Mockito +import org.springframework.transaction.TransactionDefinition +import org.springframework.transaction.support.AbstractPlatformTransactionManager +import org.springframework.transaction.support.DefaultTransactionStatus +import org.springframework.transaction.support.TransactionTemplate import java.time.LocalDateTime class ChargeEventJobServiceTest { @@ -61,6 +65,19 @@ class ChargeEventJobServiceTest { Mockito.verify(memberRepository, Mockito.never()).findByIdForUpdate(Mockito.anyLong()) } + @Test + fun shouldUseRequiresNewTransactionForAfterCommitImmediateProcessing() { + val service = ChargeEventJobService( + jobRepository = Mockito.mock(ChargeEventJobRepository::class.java), + chargeRepository = Mockito.mock(ChargeRepository::class.java), + memberRepository = Mockito.mock(MemberRepository::class.java), + transactionManager = RecordingTransactionManager() + ) + val transactionTemplate = service.transactionTemplateForTest() + + assertEquals(TransactionDefinition.PROPAGATION_REQUIRES_NEW, transactionTemplate.propagationBehavior) + } + private fun job( id: Long, memberId: Long = 10L, @@ -87,3 +104,16 @@ class ChargeEventJobServiceTest { return Member(password = "pw", nickname = "tester").also { it.id = id } } } + +private fun ChargeEventJobService.transactionTemplateForTest(): TransactionTemplate { + val field = ChargeEventJobService::class.java.getDeclaredField("transactionTemplate") + field.isAccessible = true + return field.get(this) as TransactionTemplate +} + +private class RecordingTransactionManager : AbstractPlatformTransactionManager() { + override fun doGetTransaction(): Any = Any() + override fun doBegin(transaction: Any, definition: TransactionDefinition) {} + override fun doCommit(status: DefaultTransactionStatus) {} + override fun doRollback(status: DefaultTransactionStatus) {} +}