TIL - 23.03.08

0

TIL

목록 보기
73/126

회원가입 시 이메일 인증 기능 구현을 완성한 뒤
추가적으로 DB에 저장된 정보들을 자동으로 삭제하는 기능을 만들어보았다.


처음에 가장 먼저 생각난 것은 @Scheduled 를 사용하는 방법으로

    @Scheduled(fixedDelay = 1000 * 60 * 3) // 3분
    public void deleteEmailCode() {
        LocalDateTime now = LocalDateTime.now();
        List<EmailCode> expiredCode = emailCodeRepository.findByCreatedTimeBefore(now.minusMinutes(3));
        emailCodeRepository.deleteAll(expiredCode);
    }

이렇게 작성해보았더니 삭제해야될 객체를 특정할 수 없어서 그저 3분마다 삭제하는 쿼리만 날아갈 뿐 실제 데이터는 삭제되지 않았다.

알고보니 @Scheduled를 사용한 메소드의 반환 타입은 항상 void여야 하고, 파라미터 값을 전달받을 수 없었다.


두번째 시도해본 방법은 sendEmail 메소드 실행할 때 마지막에 Timer를 이용해 deleteEmailCode 메소드를 실행시키는 방법이다.

// 인증 이메일 발송
    @Transactional
    @Override
    public void sendEmail(EmailCheckRequest emailCheckRequest) throws Exception {
    
        // 대충 인증코드 생성하고 메일 작성해서 보내는 코드 생략

        // 인증코드 메일 발송 후 10초 후 deleteEmailCode 실행
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                deleteEmailCode();
            }
        }, 1000 * 10);
    }

    // DB에 저장된 row를 삭제
    public void deleteEmailCode() {
        LocalDateTime now = LocalDateTime.now();
        EmailCode expiredCode = emailCodeRepository.findByCreatedTimeBefore(now.minusSeconds(10));
        emailCodeRepository.delete(expiredCode);
    }

와 이건 됐구나 싶었는데...
이번에도 삭제가 안됐다
여기서 원인이 뭔지도 모르겠고 머리만 붙잡고 원인을 찾다가 결국 알아낸 원인은...

sendEmail 메소드 안에서 타이머가 작동하고 있는데 타이머가 작동하고 10초 뒤에 deleteEmailCode가 실행되므로
이미 그 전에 sendEmail 메소드는 종료되기 때문에 삭제가 진행되지 못했던 것이다.

어떻게 보면 정말 당연한건데 이런 원인이 있다는 것은 정말 상상도 못한 이유였다 ㄴㅇㄱ


이번에는 대신 delete 메소드를 Timer의 run 안에 끼워넣어보았다.

// 인증 이메일 발송
    @Transactional
    @Override
    public void sendEmail(EmailCheckRequest emailCheckRequest) throws Exception {
    
        // 대충 인증코드 생성하고 메일 작성해서 보내는 코드 생략

        // 인증코드 메일 발송 후 10초 후 deleteEmailCode 실행
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 저장된 row를 삭제
                LocalDateTime now = LocalDateTime.now();
                EmailCode expiredCode = emailCodeRepository.findByCreatedTimeBefore(now.minusSeconds(10));
                emailCodeRepository.delete(expiredCode);
            }
        }, 1000 * 10); // 10초
    }

그런데.......

발견하기 싫었던 오류를 또 발견해버리고 말았다.
5초 간격으로 이메일이 다른 2개의 요청을 보냈더니 처음 생성된 데이터는 제대로 삭제가 되지만 두번째 생성되었던 데이터는 삭제가 되지않고 에러를 뱉어내버렸다.
Timer 객체가 동일한 TimerTask 객체를 사용하기 때문에, TimerTask 객체의 인스턴스 변수에 저장된 데이터를 구분할 수 없어서 여러 호출에 대한 데이터를 따로 저장하거나 삭제하는 것이 어렵기 때문에 에러가 발생했던 이유였고

결국 ScheduledExecutorService를 사용하기로 하였다.

0개의 댓글