[FitPass] 스케줄러 기능

김현정·2025년 6월 10일
0

FitPass 스케줄러 기능

FitPass의 스케줄러는 자동화 된 비즈니스 로직 처리를 담당하는 핵심 기능이다. 주로 만료된 목표들의 상태를 자동으로 업데이트하여 시스템의 데이터 일관성을 유지함.

스케줄러 아키텍처

패키지 구조

src/main/java/org/example/fitpass/domain/fitnessGoal/
└── scheduler/
    └── FitnessGoalScheduler.java

의존성 관계

FitnessGoalScheduler → FitnessGoalService → FitnessGoal Entity
                                  ↓
                       FitnessGoalRepository

메인 스케줄러 클래스

@Component
@RequiredArgsConstructor
@Slf4j
public class FitnessGoalScheduler {

    private final FitnessGoalService fitnessGoalService;

    // 매일 자정에 만료된 목표들 상태 업데이트
    @Scheduled(cron = "0 0 0 * * *")
    public void updateExpiredGoals() {
        log.info("만료된 피트니스 목표들 상태 업데이트 시작");
        try {
            fitnessGoalService.updateExpiredGoals();
            log.info("만료된 피트니스 목표들 상태 업데이트 완료");
        } catch (Exception e) {
            log.error("만료된 피트니스 목표들 상태 업데이트 중 오류 발생", e);
        }
    }
}

Cron 표현식 :

@Scheduled(cron = "0 0 0 * * *")
//              초 분 시 일 월 요일
//              0  0  0  *  *  *

0초 0분 0시(자정) 일(매일) 월(매월) *요일(모든요일)
결과 : 매일 자정 00:00:000에 실행

예외 에러 핸들링


서비스 레이어 처리 로직

@Service
public class FitnessGoalService {
    
    // 활성 목표들의 만료 상태 일괄 업데이트 (스케줄러용)
    @Transactional
    public void updateExpiredGoals() {
        List<FitnessGoal> activeGoals = fitnessGoalRepository.findByGoalStatus(GoalStatus.ACTIVE);
        activeGoals.forEach(FitnessGoal::checkAndUpdateExpiredStatus);
    }
}

엔티티 레벨 비즈니스 로직

@Entity
public class FitnessGoal {
    
    // 목표 만료 체크 및 상태 업데이트
    public void checkAndUpdateExpiredStatus() {
        if (goalStatus == GoalStatus.ACTIVE && LocalDate.now().isAfter(endDate)) {
            this.goalStatus = GoalStatus.EXPIRED;
            log.info("목표 만료 처리: Goal ID {}, 종료일 {}", this.id, this.endDate);
        }
    }
}

스케줄러 동작 원리

실행 흐름

graph TD
    A[매일 자정 00:00] --> B[FitnessGoalScheduler.updateExpiredGoals()]
    B --> C[FitnessGoalService.updateExpiredGoals()]
    C --> D[ACTIVE 상태 목표들 조회]
    D --> E[각 목표별 만료 상태 체크]
    E --> F{종료일 < 오늘?}
    F -->|Yes| G[상태를 EXPIRED로 변경]
    F -->|No| H[상태 유지]
    G --> I[로그 기록]
    H --> I
    I --> J[완료]

실시간 상태 체크 + 스케줄러 처리

FitPass는 실시간 상태 체크 + 스케줄러 처리를 동시에 사용한다.

    // 내 목표 목록 조회 (만료 상태 체크 포함)
    public List<FitnessGoalListResponseDto> getMyGoals(Long userId) {
        List<FitnessGoal> goals = fitnessGoalRepository.findByUserIdOrderByCreatedAtDesc(userId);
        
        // 만료 상태 체크 및 업데이트
        goals.forEach(FitnessGoal::checkAndUpdateExpiredStatus);

        return goals.stream().map(FitnessGoalListResponseDto::from).collect(Collectors.toList());
    }

    // 목표 상세 조회 (만료 상태 체크 포함)
    public FitnessGoalResponseDto getGoal(Long userId, Long goalId) {
        FitnessGoal fitnessGoal = fitnessGoalRepository.findByIdAndUserIdOrElseThrow(goalId, userId);
        
        // 만료 상태 체크 및 업데이트
        fitnessGoal.checkAndUpdateExpiredStatus();

        return FitnessGoalResponseDto.from(fitnessGoal);
    }

내 목표를 조회 시 실시간으로 상태를 체크하는 메서드
checkAndUpdateExpiredStatus()를 사용한다.

즉, 스케줄러와 실시간 상태를 체크를 둘 다하여 즉시성과 효율성을 모두 확보하고, 안정적으로 구현.
스케줄러는 더 확장이 가능하도록 만듦.

0개의 댓글