diff --git a/back/src/main/java/com/back/domain/mentoring/slot/repository/MentorSlotRepository.java b/back/src/main/java/com/back/domain/mentoring/slot/repository/MentorSlotRepository.java index 82c73db5..12f3e6df 100644 --- a/back/src/main/java/com/back/domain/mentoring/slot/repository/MentorSlotRepository.java +++ b/back/src/main/java/com/back/domain/mentoring/slot/repository/MentorSlotRepository.java @@ -3,6 +3,7 @@ import com.back.domain.mentoring.slot.dto.response.MentorSlotDto; import com.back.domain.mentoring.slot.entity.MentorSlot; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -24,12 +25,7 @@ public interface MentorSlotRepository extends JpaRepository { ms.mentor.member.id, ms.startDateTime, ms.endDateTime, - CASE - WHEN ms.startDateTime < CURRENT_TIMESTAMP - AND ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.AVAILABLE - THEN com.back.domain.mentoring.slot.constant.MentorSlotStatus.EXPIRED - ELSE ms.status - END, + ms.status, r.id ) FROM MentorSlot ms @@ -60,7 +56,7 @@ List findMySlots( FROM MentorSlot ms WHERE ms.mentor.id = :mentorId AND ms.status = 'AVAILABLE' - AND ms.startDateTime >= CURRENT_TIMESTAMP + AND ms.startDateTime >= :now AND ms.startDateTime < :end AND ms.endDateTime >= :start ORDER BY ms.startDateTime ASC @@ -68,7 +64,8 @@ List findMySlots( List findAvailableSlots( @Param("mentorId") Long mentorId, @Param("start") LocalDateTime start, - @Param("end") LocalDateTime end + @Param("end") LocalDateTime end, + @Param("now") LocalDateTime now ); @Query(""" @@ -100,4 +97,15 @@ boolean existsOverlappingExcept( @Param("start") LocalDateTime start, @Param("end") LocalDateTime end ); + + @Modifying + @Query(""" + UPDATE MentorSlot ms + SET ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.EXPIRED + WHERE ms.startDateTime < :now + AND ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.AVAILABLE + """) + int expirePassedSlots( + @Param("now") LocalDateTime now + ); } diff --git a/back/src/main/java/com/back/domain/mentoring/slot/service/MentorSlotService.java b/back/src/main/java/com/back/domain/mentoring/slot/service/MentorSlotService.java index 0103cecf..c9b496e4 100644 --- a/back/src/main/java/com/back/domain/mentoring/slot/service/MentorSlotService.java +++ b/back/src/main/java/com/back/domain/mentoring/slot/service/MentorSlotService.java @@ -12,6 +12,8 @@ import com.back.domain.mentoring.slot.repository.MentorSlotRepository; import com.back.global.exception.ServiceException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,6 +26,7 @@ @Service @RequiredArgsConstructor +@Slf4j public class MentorSlotService { private final MentorSlotRepository mentorSlotRepository; @@ -40,7 +43,8 @@ public List getMyMentorSlots(Mentor mentor, LocalDateTime startDa public List getAvailableMentorSlots(Long mentorId, LocalDateTime startDate, LocalDateTime endDate) { DateTimeValidator.validateTime(startDate, endDate); - return mentorSlotRepository.findAvailableSlots(mentorId, startDate, endDate); + LocalDateTime now = LocalDateTime.now(); + return mentorSlotRepository.findAvailableSlots(mentorId, startDate, endDate, now); } @Transactional(readOnly = true) @@ -147,6 +151,24 @@ private LocalDate findNextOrSameDayOfWeek(LocalDate startDate, DayOfWeek targetD } + // ===== 스케줄러 ===== + + /** + * 매 시간 30분에 지난 슬롯 만기 처리 + * - AVAILABLE -> EXPIRED + */ + @Scheduled(cron = "0 */30 * * * *") + @Transactional + public void expirePassedSlots() { + LocalDateTime now = LocalDateTime.now(); + + int updateCount = mentorSlotRepository.expirePassedSlots(now); + if (updateCount > 0) { + log.info("만료된 슬롯 {}개 업데이트 완료 at {}", updateCount, now); + } + } + + // ===== 검증 메서드 ===== private static void validateOwner(MentorSlot mentorSlot, Mentor mentor) { diff --git a/back/src/test/java/com/back/domain/mentoring/slot/service/MentorSlotServiceTest.java b/back/src/test/java/com/back/domain/mentoring/slot/service/MentorSlotServiceTest.java index 7c3870e9..faf752d7 100644 --- a/back/src/test/java/com/back/domain/mentoring/slot/service/MentorSlotServiceTest.java +++ b/back/src/test/java/com/back/domain/mentoring/slot/service/MentorSlotServiceTest.java @@ -174,8 +174,9 @@ void getAvailableMentorSlots() { ); List availableSlots = List.of(slotDto1, slotDto2); + LocalDateTime now = LocalDateTime.now(); - when(mentorSlotRepository.findAvailableSlots(mentor1.getId(), startDate, endDate)) + when(mentorSlotRepository.findAvailableSlots(mentor1.getId(), startDate, endDate, now)) .thenReturn(availableSlots); // when @@ -183,7 +184,7 @@ void getAvailableMentorSlots() { // then assertThat(result).hasSize(2); - verify(mentorSlotRepository).findAvailableSlots(mentor1.getId(), startDate, endDate); + verify(mentorSlotRepository).findAvailableSlots(mentor1.getId(), startDate, endDate, now); } }