Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
)
}
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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)
}
}
3 changes: 3 additions & 0 deletions src/main/resources/application-mysql.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down