Skip to content

Commit 96a13be

Browse files
authored
Feat: 시간 지난 슬롯 상태 변경 스케줄링 구현 (#318)
* Feat: 30분마다 예약 이력 없는 기간 지난 스케줄링 제거 * Refactor: 서버 시간 기준으로 변경
1 parent 697313b commit 96a13be

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

back/src/main/java/com/back/domain/mentoring/slot/repository/MentorSlotRepository.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.mentoring.slot.dto.response.MentorSlotDto;
44
import com.back.domain.mentoring.slot.entity.MentorSlot;
55
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Modifying;
67
import org.springframework.data.jpa.repository.Query;
78
import org.springframework.data.repository.query.Param;
89

@@ -24,12 +25,7 @@ public interface MentorSlotRepository extends JpaRepository<MentorSlot, Long> {
2425
ms.mentor.member.id,
2526
ms.startDateTime,
2627
ms.endDateTime,
27-
CASE
28-
WHEN ms.startDateTime < CURRENT_TIMESTAMP
29-
AND ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.AVAILABLE
30-
THEN com.back.domain.mentoring.slot.constant.MentorSlotStatus.EXPIRED
31-
ELSE ms.status
32-
END,
28+
ms.status,
3329
r.id
3430
)
3531
FROM MentorSlot ms
@@ -60,15 +56,16 @@ List<MentorSlotDto> findMySlots(
6056
FROM MentorSlot ms
6157
WHERE ms.mentor.id = :mentorId
6258
AND ms.status = 'AVAILABLE'
63-
AND ms.startDateTime >= CURRENT_TIMESTAMP
59+
AND ms.startDateTime >= :now
6460
AND ms.startDateTime < :end
6561
AND ms.endDateTime >= :start
6662
ORDER BY ms.startDateTime ASC
6763
""")
6864
List<MentorSlotDto> findAvailableSlots(
6965
@Param("mentorId") Long mentorId,
7066
@Param("start") LocalDateTime start,
71-
@Param("end") LocalDateTime end
67+
@Param("end") LocalDateTime end,
68+
@Param("now") LocalDateTime now
7269
);
7370

7471
@Query("""
@@ -100,4 +97,15 @@ boolean existsOverlappingExcept(
10097
@Param("start") LocalDateTime start,
10198
@Param("end") LocalDateTime end
10299
);
100+
101+
@Modifying
102+
@Query("""
103+
UPDATE MentorSlot ms
104+
SET ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.EXPIRED
105+
WHERE ms.startDateTime < :now
106+
AND ms.status = com.back.domain.mentoring.slot.constant.MentorSlotStatus.AVAILABLE
107+
""")
108+
int expirePassedSlots(
109+
@Param("now") LocalDateTime now
110+
);
103111
}

back/src/main/java/com/back/domain/mentoring/slot/service/MentorSlotService.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import com.back.domain.mentoring.slot.repository.MentorSlotRepository;
1313
import com.back.global.exception.ServiceException;
1414
import lombok.RequiredArgsConstructor;
15+
import lombok.extern.slf4j.Slf4j;
16+
import org.springframework.scheduling.annotation.Scheduled;
1517
import org.springframework.stereotype.Service;
1618
import org.springframework.transaction.annotation.Transactional;
1719

@@ -24,6 +26,7 @@
2426

2527
@Service
2628
@RequiredArgsConstructor
29+
@Slf4j
2730
public class MentorSlotService {
2831

2932
private final MentorSlotRepository mentorSlotRepository;
@@ -40,7 +43,8 @@ public List<MentorSlotDto> getMyMentorSlots(Mentor mentor, LocalDateTime startDa
4043
public List<MentorSlotDto> getAvailableMentorSlots(Long mentorId, LocalDateTime startDate, LocalDateTime endDate) {
4144
DateTimeValidator.validateTime(startDate, endDate);
4245

43-
return mentorSlotRepository.findAvailableSlots(mentorId, startDate, endDate);
46+
LocalDateTime now = LocalDateTime.now();
47+
return mentorSlotRepository.findAvailableSlots(mentorId, startDate, endDate, now);
4448
}
4549

4650
@Transactional(readOnly = true)
@@ -147,6 +151,24 @@ private LocalDate findNextOrSameDayOfWeek(LocalDate startDate, DayOfWeek targetD
147151
}
148152

149153

154+
// ===== 스케줄러 =====
155+
156+
/**
157+
* 매 시간 30분에 지난 슬롯 만기 처리
158+
* - AVAILABLE -> EXPIRED
159+
*/
160+
@Scheduled(cron = "0 */30 * * * *")
161+
@Transactional
162+
public void expirePassedSlots() {
163+
LocalDateTime now = LocalDateTime.now();
164+
165+
int updateCount = mentorSlotRepository.expirePassedSlots(now);
166+
if (updateCount > 0) {
167+
log.info("만료된 슬롯 {}개 업데이트 완료 at {}", updateCount, now);
168+
}
169+
}
170+
171+
150172
// ===== 검증 메서드 =====
151173

152174
private static void validateOwner(MentorSlot mentorSlot, Mentor mentor) {

back/src/test/java/com/back/domain/mentoring/slot/service/MentorSlotServiceTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,17 @@ void getAvailableMentorSlots() {
174174
);
175175

176176
List<MentorSlotDto> availableSlots = List.of(slotDto1, slotDto2);
177+
LocalDateTime now = LocalDateTime.now();
177178

178-
when(mentorSlotRepository.findAvailableSlots(mentor1.getId(), startDate, endDate))
179+
when(mentorSlotRepository.findAvailableSlots(mentor1.getId(), startDate, endDate, now))
179180
.thenReturn(availableSlots);
180181

181182
// when
182183
List<MentorSlotDto> result = mentorSlotService.getAvailableMentorSlots(mentor1.getId(), startDate, endDate);
183184

184185
// then
185186
assertThat(result).hasSize(2);
186-
verify(mentorSlotRepository).findAvailableSlots(mentor1.getId(), startDate, endDate);
187+
verify(mentorSlotRepository).findAvailableSlots(mentor1.getId(), startDate, endDate, now);
187188
}
188189
}
189190

0 commit comments

Comments
 (0)