refactor: schedule/hold API에서의 로깅 수정 및 동시성 테스트 추가

This commit is contained in:
이상진 2025-10-03 16:00:37 +09:00
parent 10318cab33
commit a50cbbe43e
2 changed files with 62 additions and 2 deletions

View File

@ -71,10 +71,11 @@ class ScheduleService(
id = id,
currentStatus = ScheduleStatus.AVAILABLE,
changeStatus = ScheduleStatus.HOLD
)
).also {
log.info { "[ScheduleService.holdSchedule] $it 개의 row 변경 완료" }
}
if (result == 0) {
log.info { "[ScheduleService.holdSchedule] Holding된 일정 없음: id=${id}, count = " }
throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE)
}

View File

@ -0,0 +1,59 @@
package com.sangdol.roomescape.schedule
import com.sangdol.common.types.web.HttpStatus
import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
import com.sangdol.roomescape.supports.FunSpecSpringbootTest
import com.sangdol.roomescape.supports.runTest
import io.kotest.assertions.assertSoftly
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
import org.springframework.data.repository.findByIdOrNull
import java.util.concurrent.CountDownLatch
class ScheduleConcurrencyTest(
private val scheduleRepository: ScheduleRepository
) : FunSpecSpringbootTest() {
init {
test("하나의 ${ScheduleStatus.AVAILABLE}인 일정에 대한 동시 HOLD 변경 요청이 들어오면, 가장 먼저 들어온 요청만 성공한다.") {
val user = testAuthUtil.defaultUserLogin()
val schedule = dummyInitializer.createSchedule()
withContext(Dispatchers.IO) {
val jobSize = 64
val latch = CountDownLatch(jobSize)
(1..jobSize).map {
async {
latch.countDown()
latch.await()
runTest(
token = user.second,
on = {
post("/schedules/${schedule.id}/hold")
},
expect = {
}
).extract().statusCode()
}
}.awaitAll().also {
it.count { statusCode -> statusCode == HttpStatus.OK.value() } shouldBe 1
it.count { statusCode -> statusCode == ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE.httpStatus.value() } shouldBe (jobSize - 1)
}
}
assertSoftly(scheduleRepository.findByIdOrNull(schedule.id)!!) {
this.status shouldBe ScheduleStatus.HOLD
this.holdExpiredAt.shouldNotBeNull()
}
}
}
}