[#61] 커넥션 고갈 해결을 위한 로그인 이력 저장 비동기 처리 #62

Merged
pricelees merged 9 commits from refactor/#61 into main 2025-10-14 00:28:45 +00:00
2 changed files with 12 additions and 70 deletions
Showing only changes of commit 0f1ce2a497 - Show all commits

View File

@ -1,6 +1,7 @@
package com.sangdol.roomescape.auth.business
import com.sangdol.roomescape.admin.business.AdminService
import com.sangdol.roomescape.auth.business.domain.LoginHistoryEvent
import com.sangdol.roomescape.auth.business.domain.PrincipalType
import com.sangdol.roomescape.auth.dto.LoginContext
import com.sangdol.roomescape.auth.dto.LoginCredentials
@ -12,8 +13,8 @@ import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils
import com.sangdol.roomescape.user.business.UserService
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
private val log: KLogger = KotlinLogging.logger {}
@ -25,10 +26,9 @@ const val CLAIM_STORE_ID_KEY = "store_id"
class AuthService(
private val adminService: AdminService,
private val userService: UserService,
private val loginHistoryService: LoginHistoryService,
private val jwtUtils: JwtUtils,
private val eventPublisher: ApplicationEventPublisher
) {
@Transactional(readOnly = true)
fun login(
request: LoginRequest,
context: LoginContext
@ -36,20 +36,25 @@ class AuthService(
log.info { "[login] 로그인 시작: account=${request.account}, type=${request.principalType}, context=${context}" }
val (credentials, extraClaims) = getCredentials(request)
val event = LoginHistoryEvent(
id = credentials.id,
type = request.principalType,
ipAddress = context.ipAddress,
userAgent = context.userAgent
)
try {
verifyPasswordOrThrow(request, credentials)
val accessToken = jwtUtils.createToken(subject = credentials.id.toString(), claims = extraClaims)
loginHistoryService.createSuccessHistory(credentials.id, request.principalType, context)
eventPublisher.publishEvent(event.onSuccess())
return credentials.toResponse(accessToken).also {
log.info { "[login] 로그인 완료: account=${request.account}, context=${context}" }
}
} catch (e: Exception) {
loginHistoryService.createFailureHistory(credentials.id, request.principalType, context)
eventPublisher.publishEvent(event.onFailure())
when (e) {
is AuthException -> {
log.info { "[login] 로그인 실패: account = ${request.account}" }

View File

@ -1,63 +0,0 @@
package com.sangdol.roomescape.auth.business
import com.sangdol.common.persistence.IDGenerator
import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryEntity
import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryRepository
import com.sangdol.roomescape.auth.dto.LoginContext
import com.sangdol.roomescape.auth.business.domain.PrincipalType
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
private val log: KLogger = KotlinLogging.logger {}
@Service
class LoginHistoryService(
private val loginHistoryRepository: LoginHistoryRepository,
private val idGenerator: IDGenerator,
) {
@Transactional(propagation = Propagation.REQUIRES_NEW)
fun createSuccessHistory(
principalId: Long,
principalType: PrincipalType,
context: LoginContext
) {
createHistory(principalId, principalType, success = true, context = context)
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
fun createFailureHistory(
principalId: Long,
principalType: PrincipalType,
context: LoginContext
) {
createHistory(principalId, principalType, success = false, context = context)
}
private fun createHistory(
principalId: Long,
principalType: PrincipalType,
success: Boolean,
context: LoginContext
) {
log.info { "[createHistory] 로그인 이력 저장 시작: id=${principalId}, type=${principalType}, success=${success}" }
runCatching {
LoginHistoryEntity(
id = idGenerator.create(),
principalId = principalId,
principalType = principalType,
success = success,
ipAddress = context.ipAddress,
userAgent = context.userAgent,
).also {
loginHistoryRepository.save(it)
log.info { "[createHistory] 로그인 이력 저장 완료: principalId=${principalId}, historyId=${it.id}" }
}
}.onFailure {
log.warn { "[createHistory] 로그인 이력 저장 중 예외 발생: message=${it.message} id=${principalId}, type=${principalType}, success=${success}, context=${context}" }
}
}
}