20240305 (화) 최종 프로젝트 티켓레이더 2주차 - Lock 구현

2024. 3. 5. 17:49TIL

오늘 작업한 내용

1. MemberRepositoryTest

 

package com.codersgate.ticketraider.domain.member.repository

import com.codersgate.ticketraider.domain.member.entity.Member
import com.codersgate.ticketraider.domain.member.entity.MemberRole
import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.test.annotation.Rollback
import org.springframework.test.context.ActiveProfiles
import org.springframework.transaction.annotation.Transactional

@DataJpaTest
@Transactional
//@Import(JpaBaseConfiguration::class)
@Rollback(value = false)
@ActiveProfiles("test")
class MemberRepositoryTest {

    @Autowired
    lateinit var memberRepository: MemberRepository

    @Test
    fun memberInsertTest() {
        // given
        val newMember = Member(
            nickname = "testMember",
            email = "test@test.com",
            password = "123456",
            role = MemberRole.MEMBER
        )

        // when
        val savedMember = memberRepository.save(newMember)

        // then
        assertThat(savedMember).isNotNull
    }
}

 

멤버 회원가입시 레포지토리에 저장이 잘 되는지 확인하는 테스트코드

 

2. Pub-Sub 락 구현 및 AOP 과정

package com.codersgate.ticketraider.global.common.aop.redis.lock

import com.codersgate.ticketraider.domain.ticket.dto.CreateTicketRequest
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.reflect.MethodSignature
import org.redisson.api.RedissonClient
import org.springframework.stereotype.Component
import java.util.concurrent.TimeUnit

@Aspect
@Component
class PubSubLockAspect(
    private val redissonClient: RedissonClient,
) {

    @Around("@annotation(com.codersgate.ticketraider.global.common.aop.redis.lock.PubSubLock) && args(..,createTicketRequest)")
    fun runPubSubLock(joinPoint: ProceedingJoinPoint, createTicketRequest: CreateTicketRequest) {
        val methodSignature = joinPoint.signature as MethodSignature
        val annotation = methodSignature.method.getAnnotation(PubSubLock::class.java)

        val lock = redissonClient.getLock(generateKey(createTicketRequest))
        try {
            //획득시도 시간, 락 점유 시간
            val available =lock.tryLock(5, 1, TimeUnit.SECONDS)

            if (!available) {
                println("lock 획득 실패")
                return
            }
            joinPoint.proceed()
//        } catch (e: InterruptedException) {
//            throw RuntimeException(e)
        } finally {
            lock.unlock()
        }
    }
    private fun generateKey(request: CreateTicketRequest): String {
        val key = "ID : ${request.eventId}, ${request.date} : ${request.grade}-${request.seatNo}"
        return key
    }
}

 

3. 추가 테스트코드 구현 계획

 

지금 현재 작성된 테스트코드로는

 

티켓 예매(동시성제어 관련) 테스트코드

멤버 회원가입후 레포지토리 저장 확인 테스트코드

 

이렇게 2개가 있다.

 

개인적인 욕심으로는 유저관련 테스트코드 1개에 관리자 관련 테스트코드2개정도를 더 추가해보고 싶다.

유저관련 후보

  • 티켓 스테이터스가 결제가 완료되면 결제 완료 상태로 바뀐다. << 이는 현재 티켓 스테이터스가 구현완료되면 작성해볼 예정

관리자관련 후보

  • 소프트딜리트 및 영속성 전파 : 상위 테이블에서 소프트딜리트가 이루어지면 관계있는 하위테이블에서도 소프트딜리트가 이루어져야한다.
  • 이벤트생성에 따른 가격, 좌석 컬럼 자동생성 : 현재 이벤트가 생성되면 자동으로 가격, 좌석 컬럼이 생성되게 해놨는데 이를 테스트코드로 표현한다면 어떻게 해야할지 살짝 고민된다..

오늘부터 기술면접 대비 질문-답변 을 작성할 예정이다. 

따라서 TIL에 약간 소홀해질수도 있는데 최대한 같이 써볼수 있도록 해보겠다..