2023.09.07.목.TIL

heeh·2023년 9월 11일

TIL

목록 보기
81/82
post-thumbnail

2023.09.07.목.TIL

회원 탈퇴

  • withdrawals table의 저장되는 컬럼의 user_id에 null값이 찍힘

    Withdrawal withdrawal = Withdrawal.builder()
                    .id(targetUser.getId())
                    .requestTime(now)
                    .scheduledDeletionTime(scheduledDeletionTime)
                    .status(WithdrawalStatusEnum.PENDING) // 탈퇴 상태를 대기 중으로 설정
                    .build();
    • .id(targetUser.getId())를 .user(targetUser) // 사용자 엔티티를 설정으로 수정
      LocalDateTime now = LocalDateTime.now();
              LocalDateTime scheduledDeletionTime = now.plusMinutes(1);
              Withdrawal withdrawal = Withdrawal.builder()
                      .user(targetUser) // 사용자 엔티티를 설정
                      .requestTime(now)
                      .scheduledDeletionTime(scheduledDeletionTime)
                      .status(WithdrawalStatusEnum.PENDING)
                      .build();
  • withdrawals table의 정보와 users table의 정보가 여전히 삭제되지 않음

  • withdrawals table에 있는 정보가 만료기간이 다 되면 삭제될 때 users table에 있는 같은 정보도 사라지게 만들려면….

    • public class User 연관 관계
      @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
          private List<Withdrawal> withdrawals = new ArrayList<>();
    • public class Withdrawal 연관 관계
      @ManyToOne
          @JoinColumn(name = "user_id")
          private User user;
  • @Scheduled(fixedRate = 60000) 스케줄링이 작동되는 주기의 시간과
    LocalDateTime standardTime = LocalDateTime.now().minusMinutes(5); // 현재 시간보다 n시간 전에 있었던 것을 삭제 -> n시간이 유예기간 회원 탈퇴와 관련된(다른 기능도) 기능의 정보를 담아주는 시간이 별개

    • LocalDateTime.now().minusMinutes(5)는 5분의 시간이 필요!
      • @Scheduled(fixedRate = 60000) 스케줄러가 5번 이상이 작동되어야 한다!
         
    • 스케줄러가 1, 2, 3, 4 번 작동 될때는 LocalDateTime… 가 작동되지 않는다!
  • wuthdrawals table에서 삭제되면 users table에서도 삭제 해야하는데, 딱히 연관 관계의 문제는 아니었다!
    → @ManyToOne 안에 cascade = CascadeType.REMOVE를 주면 삭제할 수 있지만, 적합하지 않음
    - 해결 방법 : 스케줄러에서 userRepository를 불러와서 직접 삭제해주어야 한다

  • @Scheduled(fixedRate = 600000) // 매 분마다 스케줄링가 돌아야 삭제가 된다!
    @Scheduled(fixedRate = 600000)가 돌아가지 않고 LocalDateTime standardTime = LocalDateTime.now().minusMinutes(5);의 유예기간이 끝나도 삭제되지 않는다
    - 유예기간은 30일로 하되, 그 처리하는 기간은 30일 보다 더 적은 날짜로 일을 시켜야 유예기간 30일이 지켜진다
    - ex) 유예기간은 30일, 스케줄드는 매일 자정!

  • 해야 할 것

    • 유예기간 동안 또 다시 탈퇴 신청을 하면 또 탈퇴하지 못하고 “이미 탈퇴 중입니다” 를 반환하게 하기
      → Withdrawal Repository에서 targetUser를 찾아…
    • 유예 기간 동안 탈퇴를 취소하는 것을 만들어야 한다!!!
public static class Authority {
        public static final String USER = "ROLE_USER";
        public static final String ADMIN = "ROLE_ADMIN";
    }
  • enum 역할 추가 - DENY

  • UserService - public ResponseEntity withdrawUser(User user)에 @Transactional를 걸어주고 enum 역할의 DENY로 변경할 수 있도록! → 팀장님이 도와주고… 완료

    • DENY 역할의 user는 회원 탈퇴 신청 취소를 요구 받고 계정이 비활성화 될 수 있다
      • JwtAuthenticationFilter - 시큐리티와 관련
        → 팀장님이 하신다고…
  • withdrawal table의 expire_time 시간 나타내기

    // Withdrawal 엔티티를 생성하고 예정 탈퇴 시간을 설정
            LocalDateTime requestTime = LocalDateTime.now();
            LocalDateTime expireTime = LocalDateTime.now().plusMinutes(1);
    
            // 이미 탈퇴 진행 중인지 확인
            Optional<Withdrawal> existingWithdrawal = withdrawalRepository.findByUserId(targetUser.getId());
            if (existingWithdrawal.isPresent()) {
                return ResponseEntity.badRequest().body("이미 탈퇴 진행 중입니다.");
            } else{
                Withdrawal withdrawal = Withdrawal.builder()
                        .user(targetUser) // 사용자 엔티티를 설정
                        .requestTime(requestTime)
                        .expireTime(expireTime)
                        .build();
                withdrawalRepository.save(withdrawal); // Withdrawal 정보 저장
    • LocalDateTime expireTime = LocalDateTime.now().plusMinutes(1);와 .expireTime(expireTime)를 추가
    • plusMinutes(1)은 에 있는 LocalDateTime standardTime = LocalDateTime.now().minusSeconds(1);의 minusSeconds(1)와 같은 설정을 해줘야 endTime을 알 수 있다
  • 시간 계산을 볼 수 있도록 log 추가

      			log.info("현재 시간: {}", currentDateTime);
            log.info("탈퇴 요청: {}", standardTime);
            log.info("현재 시간 - 탈퇴 요청 = 탈퇴 유예 기간");
  • 스케줄러 하루에 3번, 유예 기간 7일으로 설정하기!

    • @Scheduled(fixedRate = 60000)처럼 1분(n분) 마다 실행되는 것이 아닌 시간 정해주기!
    • @Scheduled(cron = "0 30 7,15,23 * * *")으로 바꿔주고 매일 7시 30분, 15시 30분, 23시 30분에 작업을 실행하도록 설정
      • 이유?
        1. 서울 API 업데이트 @Scheduled(cron = "0 0 6,23 * * *") 시간 피하기(혹시 모를 과부화, 트래픽 대비)
        2. 0시 같은 일(날)이 넘어가는 시간에 설정하면 스케줄러 발동이 애매해질 수도 있기 때문에 피해서 선택
  • Scheduled 어노테이션을 사용하여 스케줄러의 시간을 설정

    1. 고정 속도로 스케줄링 (fixedRate):

      • fixedRate 속성을 사용하여 일정한 간격으로 작업을 실행할 수 있습니다. 예를 들어, 아래의 코드는 1분마다 작업을 실행합니다.
      javaCopy code
      @Scheduled(fixedRate = 60000)
      public void myScheduledTask() {
          // 작업 내용
      }
    2. 고정 지연 시간으로 스케줄링 (fixedDelay):

      • fixedDelay 속성을 사용하여 이전 작업이 완료된 후 일정한 지연 시간 후에 작업을 실행할 수 있습니다. 예를 들어, 아래의 코드는 작업이 완료된 후 1분 후에 다시 작업을 실행합니다.
      javaCopy code
      @Scheduled(fixedDelay = 60000)
      public void myScheduledTask() {
          // 작업 내용
      }
    3. Cron 표현식 사용:

      • Cron 표현식을 사용하여 복잡한 스케줄을 정의할 수 있습니다. Cron 표현식은 초, 분, 시간, 일 등을 세밀하게 제어할 수 있습니다. 예를 들어, 매일 오전 2시에 작업을 실행하려면 다음과 같이 할 수 있습니다.
      javaCopy code
      @Scheduled(cron = "0 0 2 * * ?")
      public void myScheduledTask() {
          // 작업 내용
      }
      • @Scheduled(cron = "0 0 2 * * ?") 에서 ?는 무엇일까? Cron 표현식에서 ?는 "일자를 지정하지 않음"을 나타내는 특수한 값입니다. Cron 표현식은 초, 분, 시, 일, 월, 주(요일)을 지정하는데 사용됩니다. ?는 이 중 "일" 필드를 나타내며, 이 필드를 표시하지 않음을 의미합니다. ?를 사용하는 이유는 몇몇 Cron 표현식에서 "일" 필드와 "요일" 필드를 동시에 지정할 때 유용합니다. 예를 들어, 매주 월요일에 작업을 실행하려면 다음과 같이 Cron 표현식을 사용할 수 있습니다:
        kotlinCopy code
        @Scheduled(cron = "0 0 * * MON ?")
        
        이렇게 하면 "일" 필드는 ?로 지정되어 있으며, "요일" 필드는 MON으로 지정되어 월요일에만 작업이 실행됩니다. 일과 요일 중 하나만 지정하고 나머지는 ?로 표시하여 각각의 필드를 독립적으로 조절할 수 있습니다.
      • @Scheduled(cron = "0 0 6,23 * * *") @Scheduled(cron = "0 0 6,23 * * *")는 Spring Framework에서 사용되는 Cron 표현식으로, 주어진 시간에 작업을 실행하는 방식을 나타냅니다. 이 표현식은 다음과 같이 해석됩니다:
        • 초 (Seconds): 0

        • 분 (Minutes): 0

        • 시 (Hours): 6 또는 23

        • 일 (Day of month): 모든 날짜

        • 월 (Month): 모든 달

        • 요일 (Day of week): 모든 요일

          따라서 이 Cron 표현식은 매일 오전 6시와 오후 11시에 작업을 실행하도록 설정됩니다. 즉, 하루에 두 번 작업이 실행됩니다.

    4. 초기 지연 시간 설정:

      • initialDelay 속성을 사용하여 스케줄러를 시작할 때 초기 지연 시간을 설정할 수 있습니다. 예를 들어, 스케줄러를 시작한 후 30초를 기다린 후에 작업을 실행하려면 다음과 같이 할 수 있습니다.
      javaCopy code
      @Scheduled(initialDelay = 30000, fixedRate = 60000)
      public void myScheduledTask() {
          // 작업 내용
      }
  • 확인하기!

    • 시간 맞추기

      • UserService - public ResponseEntity withdrawUser(User user)

        // Withdrawal 엔티티를 생성하고 예정 탈퇴 시간을 설정
                LocalDateTime requestTime = LocalDateTime.now();
                LocalDateTime expireTime = LocalDateTime.now().plusDays(7);
        
                // 이미 탈퇴 진행 중인지 확인
                Optional<Withdrawal> existingWithdrawal = withdrawalRepository.findByUserId(targetUser.getId());
                if (existingWithdrawal.isPresent()) {
                    return ResponseEntity.badRequest().body("이미 탈퇴 진행 중입니다.");
                } else{
                    Withdrawal withdrawal = Withdrawal.builder()
                            .user(targetUser) // 사용자 엔티티를 설정
                            .requestTime(requestTime)
                            .expireTime(expireTime)
                            .build();
                    withdrawalRepository.save(withdrawal); // Withdrawal 정보 저장
      • public class WithdrawalScheduler

        LocalDateTime standardTime = LocalDateTime.now().minusDays(7);
      • withdrawals table

        • 2023-09-07 19:33에 탈퇴 신청을 했으니 2023-09-14 19:33에 탈퇴 완료 예정
    • 스케줄러

      • @Scheduled(cron = "0 30 7,15,23 * * *"), 즉 7시 30분/15시 30분/23시 30분에 스케줄러가 작동
      • user_id 17번의 user의 정보는 2023-09-14 19:33에 삭제되어 회원 탈퇴 완료 예정
      • 하지만 스케줄러는 15시 30분에 이미 발동 했기 때문에 다음 발동 시간인 23시 30분에 삭제될 것으로 예상
        • 19:33에 탈퇴 예정이지만 스케줄러 작동해야 탈퇴 완료(회원 정보 삭제)가 되기 때문에 다음 발동 시간인 23시 30분까지 약 5~6시간이 더 걸릴 것으로 예상
  • Redis → Scheduled…. 헤매고 어지럽고 어려웠던 기능이 끝났다

    • Redis에서 헤매고 결국 적합하지 않은 기능이어서 놓아주었고 Scheduled는 처음 해봤지만서도 잘못된 정보로 시작해서 많이 헤맸다
    • 탈퇴 유예기간 동안 탈퇴 취소, 회원 비활성화를 정복하지 못해서 아쉽다
  • 다음거는… 아마도 레디스를 중점으로 알람 기능! 소켓도 필요!

    • 채팅 기능은 소켓을 이용해서 하는 것 같던데 이것도 하고 싶다
profile
공부하자개발하자으쌰으쌰

0개의 댓글