diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/controller/NotificationController.java b/src/main/java/com/backendsystemdesignlab/notification/notification/controller/NotificationController.java index 6fa4fcc..5f14af9 100644 --- a/src/main/java/com/backendsystemdesignlab/notification/notification/controller/NotificationController.java +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/controller/NotificationController.java @@ -21,7 +21,7 @@ public class NotificationController { @PostMapping public ResponseEntity send(@Valid @RequestBody SendNotificationRequest request) { SendNotificationResponse response = notificationService.send(request); - return ResponseEntity.accepted().body(response); // 아직 실제 전송이 완료된 게 아니라 요청 접수 단계 (202 Accepted) + return ResponseEntity.ok(response); } } diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/EmailProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/EmailProvider.java new file mode 100644 index 0000000..d57d1a7 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/EmailProvider.java @@ -0,0 +1,5 @@ +package com.backendsystemdesignlab.notification.notification.provider; + +public interface EmailProvider { + ProviderResult send(String email); +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/ProviderResult.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/ProviderResult.java new file mode 100644 index 0000000..45d4544 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/ProviderResult.java @@ -0,0 +1,6 @@ +package com.backendsystemdesignlab.notification.notification.provider; + +public record ProviderResult( + boolean success +) { +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/PushProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/PushProvider.java new file mode 100644 index 0000000..78c7aa3 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/PushProvider.java @@ -0,0 +1,5 @@ +package com.backendsystemdesignlab.notification.notification.provider; + +public interface PushProvider { + ProviderResult send(String deviceToken); +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/SmsProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/SmsProvider.java new file mode 100644 index 0000000..6aac852 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/SmsProvider.java @@ -0,0 +1,5 @@ +package com.backendsystemdesignlab.notification.notification.provider; + +public interface SmsProvider { + ProviderResult send(String phoneNumber); +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockEmailProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockEmailProvider.java new file mode 100644 index 0000000..576c3b0 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockEmailProvider.java @@ -0,0 +1,24 @@ +package com.backendsystemdesignlab.notification.notification.provider.mock; + +import com.backendsystemdesignlab.notification.notification.provider.EmailProvider; +import com.backendsystemdesignlab.notification.notification.provider.ProviderResult; +import org.springframework.stereotype.Component; + +@Component +public class MockEmailProvider implements EmailProvider { + + @Override + public ProviderResult send(String deviceToken) { + simulateDelay(); + return new ProviderResult(true); + } + + private void simulateDelay() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockPushProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockPushProvider.java new file mode 100644 index 0000000..36bf887 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockPushProvider.java @@ -0,0 +1,24 @@ +package com.backendsystemdesignlab.notification.notification.provider.mock; + +import com.backendsystemdesignlab.notification.notification.provider.ProviderResult; +import com.backendsystemdesignlab.notification.notification.provider.PushProvider; +import org.springframework.stereotype.Component; + +@Component +public class MockPushProvider implements PushProvider { + + @Override + public ProviderResult send(String deviceToken) { + simulateDelay(); + return new ProviderResult(true); + } + + private void simulateDelay() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockSmsProvider.java b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockSmsProvider.java new file mode 100644 index 0000000..c07c252 --- /dev/null +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/provider/mock/MockSmsProvider.java @@ -0,0 +1,24 @@ +package com.backendsystemdesignlab.notification.notification.provider.mock; + +import com.backendsystemdesignlab.notification.notification.provider.ProviderResult; +import com.backendsystemdesignlab.notification.notification.provider.SmsProvider; +import org.springframework.stereotype.Component; + +@Component +public class MockSmsProvider implements SmsProvider { + + @Override + public ProviderResult send(String deviceToken) { + simulateDelay(); + return new ProviderResult(true); + } + + private void simulateDelay() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } +} diff --git a/src/main/java/com/backendsystemdesignlab/notification/notification/service/NotificationService.java b/src/main/java/com/backendsystemdesignlab/notification/notification/service/NotificationService.java index b40d91f..e73acea 100644 --- a/src/main/java/com/backendsystemdesignlab/notification/notification/service/NotificationService.java +++ b/src/main/java/com/backendsystemdesignlab/notification/notification/service/NotificationService.java @@ -1,9 +1,14 @@ package com.backendsystemdesignlab.notification.notification.service; +import com.backendsystemdesignlab.notification.notification.domain.DeliveryStatus; import com.backendsystemdesignlab.notification.notification.domain.Notification; import com.backendsystemdesignlab.notification.notification.domain.NotificationDelivery; import com.backendsystemdesignlab.notification.notification.dto.SendNotificationRequest; import com.backendsystemdesignlab.notification.notification.dto.SendNotificationResponse; +import com.backendsystemdesignlab.notification.notification.provider.EmailProvider; +import com.backendsystemdesignlab.notification.notification.provider.ProviderResult; +import com.backendsystemdesignlab.notification.notification.provider.PushProvider; +import com.backendsystemdesignlab.notification.notification.provider.SmsProvider; import com.backendsystemdesignlab.notification.notification.repository.NotificationDeliveryRepository; import com.backendsystemdesignlab.notification.notification.repository.NotificationRepository; import com.backendsystemdesignlab.notification.user.domain.NotificationChannel; @@ -31,6 +36,10 @@ public class NotificationService { private final NotificationPreferenceRepository preferenceRepository; private final NotificationRepository notificationRepository; private final NotificationDeliveryRepository deliveryRepository; + private final PushProvider pushProvider; + private final SmsProvider smsProvider; + private final EmailProvider emailProvider; + @Transactional public SendNotificationResponse send(SendNotificationRequest request) { @@ -89,6 +98,19 @@ public SendNotificationResponse send(SendNotificationRequest request) { deliveryRepository.saveAll(deliveries); + notification.startProcessing(); + + sendDeliveries(deliveries); + + boolean allSucceeded = deliveries.stream() + .allMatch(delivery -> delivery.getStatus() == DeliveryStatus.SENT); + + if (allSucceeded) { + notification.complete(); + } else { + notification.fail(); + } + return new SendNotificationResponse( notification.getId(), notification.getStatus(), @@ -96,6 +118,25 @@ public SendNotificationResponse send(SendNotificationRequest request) { ); } + private void sendDeliveries(List deliveries) { + + for (NotificationDelivery delivery : deliveries) { + delivery.recordAttempt(); + + ProviderResult result = switch (delivery.getChannel()) { + case PUSH -> pushProvider.send(delivery.getDestination()); + case SMS -> smsProvider.send(delivery.getDestination()); + case EMAIL -> emailProvider.send(delivery.getDestination()); + }; + + if (result.success()) { + delivery.markSent(); + } else { + delivery.markFailed(); + } + } + } + private void createPushDeliveries(User user, Notification notification, List deliveries) { List devices = userDeviceRepository.findAllByUserIdAndActiveTrue(user.getId());