Spring - 동시성 제어 테스트 코드 작성하기(Redisson, H2)

김상엽·2024년 3월 21일
1

Spring

목록 보기
19/26
post-thumbnail

TIL

동시성 제어 테스트(Redisson을 통한 분산 락)

    @Transactional
    public CardStatusResponse updateCard(Long cardId, CardUpdateRequest cardUpdateRequest, User user) {
        Card card = getCardById(cardId);

        if(!user.getId().equals(card.getOwner().getId()))
            throw new IllegalArgumentException("해당 카드를 수정할 권한이 없습니다.");

        RLock lock = redissonClient.getFairLock("card:" + cardId);
        try{
            if(lock.tryLock(10, 60, TimeUnit.SECONDS)){
                try{
                    card.update(cardUpdateRequest);
                } finally {
                    lock.unlock();
                }
            }
            else{
                throw new IllegalArgumentException("다른 유저가 이미 수정중입니다.");
            }
        } catch (InterruptedException e){
            Thread.currentThread().interrupt();
        }
        return new CardStatusResponse(201, "OK", card.getId());
    }
  • Redisson을 사용하여 카드 업데이트 함수에 분산락을 적용하였다.

테스트 코드

    @Test
    public void updateCardConcurrencyTest() throws InterruptedException{
        User user = new User(1L);
        int numberOfThreads = 10;
        // 쓰레드 생성
        ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
        // 주어진 수 만큼 이벤트를 기다림
        CountDownLatch latch = new CountDownLatch(numberOfThreads);

        for (int i = 1; i <= numberOfThreads; i++) {
            // 각 쓰레드에서 사용할 요청 생성
            CardUpdateRequest cardUpdateRequest = new CardUpdateRequest(1L, "Update Name " + i,
                "Update Description " + i, "Update Color " + i, "startDate", "endDate");

            int finalI = i;
            executorService.submit(() -> {
                try {
                    System.out.println(finalI + "번째 쓰레드 접근 시작");
                    cardService.updateCard(1L, cardUpdateRequest, user);
                } finally {
                    latch.countDown();
                    System.out.println(finalI + "번째 쓰레드 접근 종료");
                }
            });
        }

        latch.await(); // 모든 쓰레드의 작업이 완료될 때까지 대기
        executorService.shutdown();
    }
  • 10개의 쓰레드에서 동시에 카드를 수정하도록 테스트 코드를 구현하였다.

테스트 결과

  • 쓰레드들이 순차적으로 접근하면서 테스트가 잘 수행되었다.
  • 하지만 문제가 있다.
  • 테스트가 끝나면 DB에 테스트 결과가 남아버린다.
  • 그래서 매번 테스트를 다시 진행할때 마다 Drop Table을 했었다.

H2 Database

  • H2 Database는 자바로 작성된 관계형 데이터베이스 관리 시스템이다.
  • 특징으로는 In-Memory 데이터베이스이기 때문에 실행할때마다 초기화된다!

H2 in Memory DB

  • H2의 적용법은 간단하다.
  • application.properties에 연결해주고, 의존성 추가만 해주면 끝이다!
  • 평소에는 MySQL로 작동하지만 테스트를 진행할때는 H2로 작동하게 하려고 한다.
  • 테스트용 환경을 따로 구축하기 위해서는 test 디렉토리에 application.properties를 따로 만들어주면 test할때만 적용된다!

테스트 코드에 H2 적용하기

  • 테스트용 application.properties만 만들어주면 적용은 끝이다!

테스트 결과(H2 적용후)

  • 테스트는 이전과 동일하게 동작하지만 MySQL이 아닌 H2로 동작하기에 DB에 아무것도 남지 않는다.

오늘의 회고

사실 분산락을 통해 동시성 제어하는 기능을 구현하였지만
이번 프로젝트에는 딱히 동시성을 제어할 부분이 없었다.
그래도 이제는 할줄 안다는것에 의미를 두려고 한다!

profile
개발하는 기록자

0개의 댓글