Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class NotificationController {
@PostMapping
public ResponseEntity<SendNotificationResponse> send(@Valid @RequestBody SendNotificationRequest request) {
SendNotificationResponse response = notificationService.send(request);
return ResponseEntity.accepted().body(response); // 아직 실제 전송이 완료된 게 아니라 요청 접수 단계 (202 Accepted)
return ResponseEntity.ok(response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.backendsystemdesignlab.notification.notification.provider;

public interface EmailProvider {
ProviderResult send(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.backendsystemdesignlab.notification.notification.provider;

public record ProviderResult(
boolean success
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.backendsystemdesignlab.notification.notification.provider;

public interface PushProvider {
ProviderResult send(String deviceToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.backendsystemdesignlab.notification.notification.provider;

public interface SmsProvider {
ProviderResult send(String phoneNumber);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -89,13 +98,45 @@ 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(),
deliveries.size()
);
}

private void sendDeliveries(List<NotificationDelivery> 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<NotificationDelivery> deliveries) {
List<UserDevice> devices = userDeviceRepository.findAllByUserIdAndActiveTrue(user.getId());

Expand Down