From 8ef267b8c4746ede165f2558e3580b7992800380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:08:12 +0900 Subject: [PATCH 1/6] =?UTF-8?q?Feat:=20build.gradle=EC=97=90=20=EB=A0=88?= =?UTF-8?q?=EB=94=94=EC=8A=A4=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index ee7d3df..eb1d19e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -53,6 +53,9 @@ dependencies { // Development tools developmentOnly("org.springframework.boot:spring-boot-devtools") + // REDIS + implementation("org.springframework.boot:spring-boot-starter-data-redis") + // Test dependencies testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") From 9a4ba57048ff7784c07ccc442e8a24233691c39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:09:03 +0900 Subject: [PATCH 2/6] =?UTF-8?q?Feat:=20QueueTokenService=20interface=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - domain.queue 패키지에 QueueTokenService 인터페이스를 추가하여 대기열 토큰 관리 로직을 캡슐화함. - 이 인터페이스는 토큰 저장, 조회, 삭제 기능을 정의함. --- .../domain/queue/QueueTokenService.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenService.kt diff --git a/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenService.kt b/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenService.kt new file mode 100644 index 0000000..dff87a8 --- /dev/null +++ b/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenService.kt @@ -0,0 +1,7 @@ +package io.hhplus.concertreservationservice.domain.queue + +interface QueueTokenService { + fun saveQueueToken(token: String, userId: Long) + fun getUserIdByQueueToken(token: String): Long? + fun deleteQueueToken(token: String) +} From 15ff97378571d4e4a7228a3302847de50c0ef327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:09:55 +0900 Subject: [PATCH 3/6] =?UTF-8?q?Feat:=20RedisClient=20interface=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=EC=B2=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -infrastructure.redis 패키지에 RedisClient 인터페이스와 RedisClientImpl 구현체를 추가함. - Redis와의 통신을 캡슐화하여 구현체 변경에 유연하게 대응할 수 있도록 함. --- .../infrastructure/redis/RedisClient.kt | 7 ++++++ .../infrastructure/redis/RedisClientImpl.kt | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClient.kt create mode 100644 src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClientImpl.kt diff --git a/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClient.kt b/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClient.kt new file mode 100644 index 0000000..75ad7ff --- /dev/null +++ b/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClient.kt @@ -0,0 +1,7 @@ +package io.hhplus.concertreservationservice.infrastructure.redis + +interface RedisClient { + fun set(key: String, value: String, expirationMinutes: Long) + fun get(key: String): String? + fun delete(key: String) +} \ No newline at end of file diff --git a/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClientImpl.kt b/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClientImpl.kt new file mode 100644 index 0000000..4b902d4 --- /dev/null +++ b/src/main/kotlin/io/hhplus/concertreservationservice/infrastructure/redis/RedisClientImpl.kt @@ -0,0 +1,23 @@ +package io.hhplus.concertreservationservice.infrastructure.redis + +import org.springframework.data.redis.core.StringRedisTemplate +import org.springframework.stereotype.Component +import java.util.concurrent.TimeUnit + +@Component +class RedisClientImpl( + private val redisTemplate: StringRedisTemplate +) : RedisClient { + + override fun set(key: String, value: String, expirationMinutes: Long) { + redisTemplate.opsForValue().set(key, value, expirationMinutes, TimeUnit.MINUTES) + } + + override fun get(key: String): String? { + return redisTemplate.opsForValue().get(key) + } + + override fun delete(key: String) { + redisTemplate.delete(key) + } +} From 700ae28d76df441b5a1de52f3512558fa4f6abd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:11:33 +0900 Subject: [PATCH 4/6] =?UTF-8?q?Feat:=20QueueTokenServiceImpl=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EC=B2=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - domain.queue 패키지에 QueueTokenServiceImpl 클래스를 추가하여 QueueTokenService 인터페이스를 구현함. - RedisClient를 사용하여 Redis와의 통신을 수행. - tokenExpirationMinutes를 내부에서 관리하여 캡슐화를 강화. --- .../domain/queue/QueueTokenServiceImpl.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenServiceImpl.kt diff --git a/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenServiceImpl.kt b/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenServiceImpl.kt new file mode 100644 index 0000000..4f26f37 --- /dev/null +++ b/src/main/kotlin/io/hhplus/concertreservationservice/domain/queue/QueueTokenServiceImpl.kt @@ -0,0 +1,30 @@ +package io.hhplus.concertreservationservice.domain.queue + +import io.hhplus.concertreservationservice.infrastructure.redis.RedisClient +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service + +@Service +class QueueTokenServiceImpl( + private val redisClient: RedisClient, + @Value("\${queue.token.expirationMinutes}") private val tokenExpirationMinutes: Long +) : QueueTokenService { + + private val QUEUE_TOKEN_PREFIX = "queueToken:" + + override fun saveQueueToken(token: String, userId: Long) { + val key = "$QUEUE_TOKEN_PREFIX$token" + redisClient.set(key, userId.toString(), tokenExpirationMinutes) + } + + override fun getUserIdByQueueToken(token: String): Long? { + val key = "$QUEUE_TOKEN_PREFIX$token" + val userIdStr = redisClient.get(key) + return userIdStr?.toLong() + } + + override fun deleteQueueToken(token: String) { + val key = "$QUEUE_TOKEN_PREFIX$token" + redisClient.delete(key) + } +} From 55eaa5c0d206d3bdbcd9f0b042d1d8a609f11953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:12:32 +0900 Subject: [PATCH 5/6] =?UTF-8?q?Feat:=20QueueFacade=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=98=EC=97=AC=20QueueTokenService=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - QueueFacade에서 QueueTokenService를 의존성 주입 받아 사용하도록 수정. - Redis에 직접 접근하지 않고, QueueTokenService를 통해 토큰 관리 기능을 수행. - tokenExpirationMinutes를 QueueTokenServiceImpl 내부에서 관리하도록 변경하여 캡슐화를 강화. --- .../application/queue/QueueFacade.kt | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/io/hhplus/concertreservationservice/application/queue/QueueFacade.kt b/src/main/kotlin/io/hhplus/concertreservationservice/application/queue/QueueFacade.kt index 2c3fc5e..7b1c140 100644 --- a/src/main/kotlin/io/hhplus/concertreservationservice/application/queue/QueueFacade.kt +++ b/src/main/kotlin/io/hhplus/concertreservationservice/application/queue/QueueFacade.kt @@ -1,6 +1,7 @@ package io.hhplus.concertreservationservice.application.queue import io.hhplus.concertreservationservice.domain.queue.QueueService +import io.hhplus.concertreservationservice.domain.queue.QueueTokenService import io.hhplus.concertreservationservice.domain.user.UserService import io.hhplus.concertreservationservice.exception.ErrorType import io.hhplus.concertreservationservice.exception.QueueException @@ -11,27 +12,41 @@ import org.springframework.stereotype.Service @Service class QueueFacade( private val userService: UserService, - private val queueService: QueueService + private val queueService: QueueService, + private val queueTokenService: QueueTokenService ) { fun registerInQueue(userToken: String, request: QueueRegistrationRequest): QueueTokenResponse { val userId = userService.getUserIdFromToken(userToken) val concertScheduleId = request.concertScheduleId + + // 대기열 등록 val queueEntry = queueService.registerUserInQueue(userId, concertScheduleId) val estimatedWaitTime = queueService.calculateEstimatedWaitTime(queueEntry.queuePosition) + + // 토큰을 Redis에 저장 + queueTokenService.saveQueueToken(queueEntry.queueToken, userId) + + return QueueTokenResponse( queueToken = queueEntry.queueToken, queuePosition = queueEntry.queuePosition, - estimatedWaitTime = estimatedWaitTime) + estimatedWaitTime = estimatedWaitTime + ) } fun getQueueStatus(queueToken: String): QueueTokenResponse { - val queueEntry = queueService.getQueueStatus(queueToken) - ?: throw QueueException(ErrorType.INVALID_QUEUE_TOKEN, "queueToken: $queueToken") + val userId = queueTokenService.getUserIdByQueueToken(queueToken) + ?: throw QueueException(ErrorType.INVALID_QUEUE_TOKEN, "queueToken: $queueToken") + + val queueEntry = queueService.getQueueStatus(queueToken) + ?: throw QueueException(ErrorType.INVALID_QUEUE_TOKEN, "queueToken: $queueToken") + val estimatedWaitTime = queueService.calculateEstimatedWaitTime(queueEntry.queuePosition) return QueueTokenResponse( queueToken = queueEntry.queueToken, queuePosition = queueEntry.queuePosition, - estimatedWaitTime = estimatedWaitTime) + estimatedWaitTime = estimatedWaitTime + ) } -} \ No newline at end of file +} From 3ef004cccf0a4ba0d32a23337869d1937d9d6dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=ED=9B=84?= Date: Fri, 8 Nov 2024 20:13:12 +0900 Subject: [PATCH 6/6] =?UTF-8?q?Feat:=20application.yaml=EC=97=90=20Redis?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - application.yaml 파일에 Redis 연결 정보를 추가하여 Redis 서버와의 연결을 설정함. --- src/main/resources/application-mysql.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/application-mysql.yml b/src/main/resources/application-mysql.yml index 10536ee..063fd33 100644 --- a/src/main/resources/application-mysql.yml +++ b/src/main/resources/application-mysql.yml @@ -1,4 +1,7 @@ spring: + redis: + host: localhost + port: 6379 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://db.bluebrewlab.com:3306/dbkimjusubbl