매일 저녁 9시, 내일 약속이 있는 사용자에게 알림을
매일 아침 8시, 당일 약속이 있는 사용자에게 알림을
약속 5분전 해당 사용자에게 알림을 자동으로 보내는 알림 스케줄러를 구현해야했다.
1. 구현 API
1-1. NotificationScheduler
@Component
public class NotificationScheduler {
private final NotificationService notificationService;
private final ScheduleRepository scheduleRepository;
public NotificationScheduler(NotificationService notificationService, ScheduleRepository scheduleRepository) {
this.notificationService = notificationService;
this.scheduleRepository = scheduleRepository;
}
// 매일 밤 9시, 다음 날 약속이 있는 사용자에게 알림 전송
@Scheduled(cron = "0 0 21 * * *")
@Scheduled(fixedRate = 10000) // 테스트용 애너테이션(아래 스케줄러가 10초마다 실행됨)
public void sendEveningReminder() {
LocalDateTime startOfTomorrow = LocalDateTime.now().plusDays(1).toLocalDate().atStartOfDay();
LocalDateTime endOfTomorrow = startOfTomorrow.with(LocalTime.MAX);
List<Schedule> schedulesForTomorrow = scheduleRepository.findSchedulesBetween(startOfTomorrow, endOfTomorrow);
notificationService.sendReminder(schedulesForTomorrow, "내일 예정된 약속이 있습니다.");
}
// 매일 아침 8시, 당일 약속이 있는 사용자에게 알림 전송
@Scheduled(cron = "0 0 8 * * *")
@Scheduled(fixedRate = 10000) // 테스트용 애너테이션(아래 스케줄러가 10초마다 실행됨)
public void sendMorningReminder() {
LocalDateTime startOfToday = LocalDateTime.now().toLocalDate().atStartOfDay();
LocalDateTime endOfToday = startOfToday.with(LocalTime.MAX);
List<Schedule> schedulesForToday = scheduleRepository.findSchedulesBetween(startOfToday, endOfToday);
notificationService.sendReminder(schedulesForToday, "오늘 예정된 약속이 있습니다.");
}
// 매 분의 0초에 실행하여 5분 후 시작되는 약속 조회 및 알림 전송
@Scheduled(cron = "0 * * * * *") // 매 분의 0초에 실행
public void sendFiveMinutesBeforeReminder() {
LocalDateTime fiveMinutesLater = LocalDateTime.now().plusMinutes(5);
int targetHour = fiveMinutesLater.getHour();
int targetMinute = fiveMinutesLater.getMinute();
// 5분 후의 시각에 시작하는 약속 조회
List<Schedule> schedulesStartingSoon = scheduleRepository.findSchedulesStartingAt(targetHour, targetMinute);
// 알림 전송
notificationService.sendReminder(schedulesStartingSoon, "약속 5분 전입니다. 준비하세요.");
}
}
1-2. NotificationService
@Service
@RequiredArgsConstructor
public class NotificationService {
private final UserSettingRepository userSettingRepository;
public void sendReminder(List<Schedule> schedules, String message) {
for (Schedule schedule : schedules) {
User user = schedule.getUser();
Long userId = user.getId();
if (userId != null) {
// UserSetting 테이블에서 해당 유저의 알림 설정 가져오기
UserSetting userSetting = userSettingRepository.findByUserId(userId)
.orElseThrow(() -> new IllegalArgumentException("No UserSetting found in schedule's user"));// Repository 메서드 가정
// 알림 설정 확인
if (userSetting != null && userSetting.getIsNotificationsEnabled()) {
sendNotificationToUser(schedule, message);
}
}
}
}
private void sendNotificationToUser(Schedule schedule, String message) {
// 사용자 디바이스로 알림을 보내는 로직으로 변환 해야함. (예: FCM 사용)
User user = schedule.getUser();
System.out.println(user.getName() + "님 " + message + "\n약속: " + schedule);
}
}
구현 자체에는 큰 어려움이 없다.
@Scheduled 애너테이션을 이용해 자동 알림 기능을 구현하였다.
@Scheduled(cron = "초 분 시 일 월 요일 [년]") // 설정한 시각에 메서드 실행
@Scheduled(fixedRate = N) N ms마다 메서드 실행
NotificationService의 sendNotificationToUser메서드를 차후 FCM을 적용해 클라이언트에 알림을 보내도록 코드를 수정해야한다.
현재는 FCM을 사용하려면 Apple Developer Program(12,9000원/년)에 가입해야 해 일단락하였다.
2. 고민했던 점
매일 저녁 9시, 매일 아침 8시, 약속 5분전 이 세 스케줄러를 하나의 메서드에 구현할 지, 각 메서드로 나눌지에 대한 고민이 있었다.
결국 스케줄러는 가독성을 위해 스케줄러 하나에 메서드 하나를 구현하였고 서비스계층의 sendReminder는 공통으로 사용하게 하였다. 이 코드가 성능도, 가독성도 가장 좋은 방법인 것 같다.
크게 고민했던 지점은 없다. 알림 스케줄러는 무난하게 구현하였다.
'웹개발 > Devkor-Ontime' 카테고리의 다른 글
[Devkor-Ontime][트러블슈팅] 유저계정삭제 API 호출시 외래키 제약조건으로 인한 오류 해결 (500 Internel 서버 에러) (0) | 2025.02.13 |
---|---|
[Devkor-Ontime] 친구추가 관련 기능 구현 (0) | 2025.01.28 |
[Devkor-Ontime] 성실도 관련 기능 구현 (0) | 2024.11.15 |
[Devkor-Ontime] JWT 일반로그인 구현 (0) | 2024.11.03 |