diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/Alarm.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/Alarm.java index 1ccc2b2..8a31a35 100644 --- a/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/Alarm.java +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/Alarm.java @@ -33,8 +33,9 @@ public class Alarm { @Comment("메일 발송 시간") private LocalDateTime sendTime; - @Comment("발송 여부") - private boolean isSent; + @Comment("알림 상태") + @Enumerated(EnumType.STRING) + private AlarmStatus status; public static Alarm ofImmediate(List recipients, String subject, String content) { LocalDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDateTime(); @@ -42,8 +43,8 @@ public static Alarm ofImmediate(List recipients, String subject, String .recipients(recipients) .subject(subject) .content(content) - .sendTime(now.withSecond(0)) - .isSent(false) + .sendTime(now.withSecond(0).withNano(0)) + .status(AlarmStatus.SENT) .build(); } @@ -52,12 +53,12 @@ public static Alarm ofScheduled(List recipients, String subject, String .recipients(recipients) .subject(subject) .content(content) - .sendTime(sendTime.withSecond(0)) - .isSent(false) + .sendTime(sendTime.withSecond(0).withNano(0)) + .status(AlarmStatus.RESERVED) .build(); } - public void setSent() { - this.isSent = true; + public void setStatus(AlarmStatus status) { + this.status = status; } } diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/AlarmStatus.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/AlarmStatus.java new file mode 100644 index 0000000..e6b4c9c --- /dev/null +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/entity/AlarmStatus.java @@ -0,0 +1,5 @@ +package com.yeongjin.alarmserver.domain.alarm.entity; + +public enum AlarmStatus { + RESERVED, PUBLISHED, SENT +} diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/repository/AlarmRepository.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/repository/AlarmRepository.java index c15a803..99cba62 100644 --- a/src/main/java/com/yeongjin/alarmserver/domain/alarm/repository/AlarmRepository.java +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/repository/AlarmRepository.java @@ -8,9 +8,9 @@ import java.util.List; public interface AlarmRepository extends JpaRepository { - @Query("select e.id from Alarm e where e.isSent = true") + @Query("select e.id from Alarm e where e.status = 'SENT'") List findIdsIsSent(); - @Query("select e from Alarm e where e.sendTime <= :sendTime and e.isSent = false") + @Query("select e from Alarm e where e.sendTime <= :sendTime and e.status = 'RESERVED'") List findEmailsToSend(LocalDateTime sendTime); } diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmPublisher.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmPublisher.java index 8256645..bfe236a 100644 --- a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmPublisher.java +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmPublisher.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.yeongjin.alarmserver.domain.alarm.entity.Alarm; +import com.yeongjin.alarmserver.domain.alarm.entity.AlarmStatus; import com.yeongjin.alarmserver.domain.alarm.repository.AlarmRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,6 +21,7 @@ @Service @RequiredArgsConstructor @Slf4j +@Transactional(readOnly = true) public class SendAlarmPublisher { private final RedisTemplate redisTemplate; private final AlarmRepository alarmRepository; @@ -29,21 +31,22 @@ public class SendAlarmPublisher { @Scheduled(cron = "30 * * * * *", zone = "Asia/Seoul") @Transactional public void scanDatabase() { - LocalDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDateTime().withSecond(0); + LocalDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDateTime().withSecond(0).withNano(0); log.info("Scan Database at " + now); List alarms = alarmRepository.findEmailsToSend(now); - for (Alarm alarm : alarms) { - alarm.setSent(); + for (Alarm alarm : alarms) publishToRedis(alarm); - } } + @Transactional public void publishToRedis(Alarm alarm) { try { - String message = objectMapper.writeValueAsString(alarm); + String message = objectMapper.writeValueAsString(alarm.getId()); redisTemplate.convertAndSend(channelTopic.getTopic(), message); + alarm.setStatus(AlarmStatus.PUBLISHED); } catch (JsonProcessingException e) { log.warn("Publish Message Failed"); + alarm.setStatus(AlarmStatus.RESERVED); } } } diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmService.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmService.java index 1dce504..3734c78 100644 --- a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmService.java +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmService.java @@ -12,15 +12,11 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) @Slf4j public class SendAlarmService { private final AlarmRepository alarmRepository; private final SendAlarmPublisher sendEmailPublisher; - private final SendAlarmSubscriber sendAlarmSubscriber; - private final JavaMailSender javaMailSender; - @Transactional public Long sendImmediateEmail(SendImmediateAlarmReq sendImmediateAlarmReq) { Alarm alarm = alarmRepository.save( Alarm.ofImmediate( @@ -29,7 +25,6 @@ public Long sendImmediateEmail(SendImmediateAlarmReq sendImmediateAlarmReq) { sendImmediateAlarmReq.getContent() ) ); - alarm.setSent(); sendEmailPublisher.publishToRedis(alarm); return alarm.getId(); } @@ -41,7 +36,7 @@ public Long sendScheduledEmail(SendScheduledAlarmReq sendScheduledAlarmReq) { sendScheduledAlarmReq.getRecipients(), sendScheduledAlarmReq.getSubject(), sendScheduledAlarmReq.getContent(), - sendScheduledAlarmReq.getSendTime().withSecond(0) + sendScheduledAlarmReq.getSendTime() ) ); return alarm.getId(); diff --git a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmSubscriber.java b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmSubscriber.java index e546ba6..d4f9ec3 100644 --- a/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmSubscriber.java +++ b/src/main/java/com/yeongjin/alarmserver/domain/alarm/service/SendAlarmSubscriber.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.yeongjin.alarmserver.domain.alarm.entity.Alarm; +import com.yeongjin.alarmserver.domain.alarm.entity.AlarmStatus; +import com.yeongjin.alarmserver.domain.alarm.repository.AlarmRepository; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; @@ -10,21 +12,28 @@ import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @Slf4j +@Transactional(readOnly = true) public class SendAlarmSubscriber { private final JavaMailSender javaMailSender; private final ObjectMapper objectMapper; + private final AlarmRepository alarmRepository; + @Transactional public void sendEmail(String message, String channel) throws JsonProcessingException { - log.info("Received message: " + message + " from channel: " + channel); - Alarm alarm = objectMapper.readValue(message, Alarm.class); + log.info("Receive Message from " + channel); + Long alarmId = objectMapper.readValue(message, Long.class); + Alarm alarm = alarmRepository.findById(alarmId).orElseThrow(); try { javaMailSender.send(createMimeMessage(alarm)); - } catch (MessagingException e) { - log.warn("Create Mime Message Failed"); + alarm.setStatus(AlarmStatus.SENT); + } catch (Exception e) { + log.warn("Send Email Failed"); + alarm.setStatus(AlarmStatus.RESERVED); } }