From d70bc2e909bb38d867afcac19bb49cfcc0277d79 Mon Sep 17 00:00:00 2001 From: ybchar Date: Fri, 18 Oct 2024 21:21:47 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=95=8C=EB=A6=BC=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=83=81=EC=88=98=ED=99=94=20=EB=B0=8F=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/FcmNotificationService.java | 27 +--- .../sqs/application/SqsMessageService.java | 122 +++++++++++------- .../constants/NotificationConstants.java | 12 ++ 3 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/depromeet/stonebed/global/common/constants/NotificationConstants.java diff --git a/src/main/java/com/depromeet/stonebed/domain/fcm/application/FcmNotificationService.java b/src/main/java/com/depromeet/stonebed/domain/fcm/application/FcmNotificationService.java index b44cc9e..e129b2c 100644 --- a/src/main/java/com/depromeet/stonebed/domain/fcm/application/FcmNotificationService.java +++ b/src/main/java/com/depromeet/stonebed/domain/fcm/application/FcmNotificationService.java @@ -1,5 +1,7 @@ package com.depromeet.stonebed.domain.fcm.application; +import static com.depromeet.stonebed.global.common.constants.NotificationConstants.*; + import com.depromeet.stonebed.domain.fcm.dao.FcmNotificationRepository; import com.depromeet.stonebed.domain.fcm.dao.FcmTokenRepository; import com.depromeet.stonebed.domain.fcm.domain.FcmMessage; @@ -19,7 +21,6 @@ import com.depromeet.stonebed.global.error.exception.CustomException; import com.depromeet.stonebed.global.util.MemberUtil; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.List; @@ -48,14 +49,6 @@ public class FcmNotificationService { private final MemberRepository memberRepository; private final MemberUtil memberUtil; - private static final DateTimeFormatter DATE_FORMATTER = - DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); - - private static final long FIRST_BOOST_THRESHOLD = 1; - private static final long POPULAR_THRESHOLD = 1000; - private static final long SUPER_POPULAR_THRESHOLD = 5000; - private static final int BATCH_SIZE = 10; - public void saveNotification( FcmNotificationType type, String title, @@ -79,7 +72,7 @@ public void saveNotification( public FcmNotificationResponse getNotificationsForCurrentMember(String cursor, int limit) { Member member = memberUtil.getCurrentMember(); - Pageable pageable = createPageable(limit); + Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "createdAt")); List notifications = getNotifications(cursor, member.getId(), pageable); List notificationData = convertToNotificationDto(notifications); String nextCursor = getNextCursor(notifications); @@ -87,10 +80,6 @@ public FcmNotificationResponse getNotificationsForCurrentMember(String cursor, i return FcmNotificationResponse.from(notificationData, nextCursor); } - private Pageable createPageable(int limit) { - return PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "createdAt")); - } - private List convertToNotificationDto(List notifications) { List targetIds = notifications.stream().map(FcmNotification::getTargetId).toList(); @@ -298,15 +287,13 @@ public void sendAndNotifications( private List> createBatches(List tokens) { return IntStream.range( 0, - (tokens.size() + FcmNotificationService.BATCH_SIZE - 1) - / FcmNotificationService.BATCH_SIZE) + (tokens.size() + SQS_BATCH_SIZE - 1) + / SQS_BATCH_SIZE) // ceil(tokens.size() / SQS_BATCH_SIZE .mapToObj( i -> tokens.subList( - i * FcmNotificationService.BATCH_SIZE, - Math.min( - tokens.size(), - (i + 1) * FcmNotificationService.BATCH_SIZE))) + i * SQS_BATCH_SIZE, + Math.min(tokens.size(), (i + 1) * SQS_BATCH_SIZE))) .collect(Collectors.toList()); } diff --git a/src/main/java/com/depromeet/stonebed/domain/sqs/application/SqsMessageService.java b/src/main/java/com/depromeet/stonebed/domain/sqs/application/SqsMessageService.java index b146c4b..28fe441 100644 --- a/src/main/java/com/depromeet/stonebed/domain/sqs/application/SqsMessageService.java +++ b/src/main/java/com/depromeet/stonebed/domain/sqs/application/SqsMessageService.java @@ -1,5 +1,7 @@ package com.depromeet.stonebed.domain.sqs.application; +import static com.depromeet.stonebed.global.common.constants.NotificationConstants.*; + import com.depromeet.stonebed.domain.fcm.dao.FcmTokenRepository; import com.depromeet.stonebed.domain.fcm.domain.FcmMessage; import com.depromeet.stonebed.infra.properties.SqsProperties; @@ -24,13 +26,10 @@ @RequiredArgsConstructor @Service public class SqsMessageService { - - private final SqsClient sqsClient; - private final SqsProperties sqsProperties; - private final ObjectMapper objectMapper; private final FcmTokenRepository fcmTokenRepository; + private final SqsClient sqsClient; public void sendMessage(Object message) { try { @@ -50,57 +49,82 @@ public void sendMessage(Object message) { public void sendBatchMessages( List tokens, String title, String message, String deepLink) { - // SQS 메시지의 최대 전송 크기는 10개이므로 이를 고려하여 분할합니다. - int batchSize = 10; + List failedTokens = new ArrayList<>(); - for (int i = 0; i < tokens.size(); i += batchSize) { - List batchTokens = tokens.subList(i, Math.min(i + batchSize, tokens.size())); - List entries = new ArrayList<>(); - - for (String token : batchTokens) { - try { - FcmMessage fcmMessage = FcmMessage.of(title, message, token, deepLink); - String messageBody = objectMapper.writeValueAsString(fcmMessage); - SendMessageBatchRequestEntry entry = - SendMessageBatchRequestEntry.builder() - .id(UUID.randomUUID().toString()) - .messageBody(messageBody) - .build(); - entries.add(entry); - } catch (Exception e) { - log.error("메시지 직렬화 실패: {}", e.getMessage()); - } - } + // 토큰 리스트를 10개씩 분할하여 처리 + for (int i = 0; i < tokens.size(); i += SQS_BATCH_SIZE) { + List batchTokens = + tokens.subList(i, Math.min(i + SQS_BATCH_SIZE, tokens.size())); + + List entries = + createBatchEntries(batchTokens, title, message, deepLink); if (!entries.isEmpty()) { - SendMessageBatchRequest batchRequest = - SendMessageBatchRequest.builder() - .queueUrl(sqsProperties.queueUrl()) - .entries(entries) - .build(); + sendBatchRequest(entries, failedTokens); + } + } + + // 실패한 토큰 삭제 처리 + deleteFailedTokens(failedTokens); + } + + private List createBatchEntries( + List batchTokens, String title, String message, String deepLink) { + + List entries = new ArrayList<>(); - try { - SendMessageBatchResponse batchResponse = - sqsClient.sendMessageBatch(batchRequest); - log.info("배치 메시지 전송 응답: {}", batchResponse); - // 실패한 메시지 처리 - List failedMessages = batchResponse.failed(); - for (BatchResultErrorEntry failed : failedMessages) { - log.error("메시지 전송 실패, ID {}: {}", failed.id(), failed.message()); - failedTokens.add(failed.id()); - } - - // 실패한 토큰 삭제 - for (String failedToken : failedTokens) { - fcmTokenRepository.deleteByToken(failedToken); - log.info("비활성화된 FCM 토큰 삭제: {}", failedToken); - } - - } catch (Exception e) { - log.error("SQS 배치 메시지 전송 실패: {}", e.getMessage()); - } + for (String token : batchTokens) { + try { + FcmMessage fcmMessage = FcmMessage.of(title, message, token, deepLink); + String messageBody = objectMapper.writeValueAsString(fcmMessage); + SendMessageBatchRequestEntry entry = + SendMessageBatchRequestEntry.builder() + .id(UUID.randomUUID().toString()) + .messageBody(messageBody) + .build(); + entries.add(entry); + } catch (Exception e) { + log.error("메시지 직렬화 실패: {}", e.getMessage()); } } + + return entries; + } + + private void sendBatchRequest( + List entries, List failedTokens) { + SendMessageBatchRequest batchRequest = + SendMessageBatchRequest.builder() + .queueUrl(sqsProperties.queueUrl()) + .entries(entries) + .build(); + + try { + SendMessageBatchResponse batchResponse = sqsClient.sendMessageBatch(batchRequest); + log.info("배치 메시지 전송 응답: {}", batchResponse); + + // 실패한 메시지 처리 + handleFailedMessages(batchResponse, failedTokens); + + } catch (Exception e) { + log.error("SQS 배치 메시지 전송 실패: {}", e.getMessage()); + } + } + + private void handleFailedMessages( + SendMessageBatchResponse batchResponse, List failedTokens) { + List failedMessages = batchResponse.failed(); + for (BatchResultErrorEntry failed : failedMessages) { + log.error("메시지 전송 실패, ID {}: {}", failed.id(), failed.message()); + failedTokens.add(failed.id()); + } + } + + private void deleteFailedTokens(List failedTokens) { + for (String failedToken : failedTokens) { + fcmTokenRepository.deleteByToken(failedToken); + log.info("비활성화된 FCM 토큰 삭제: {}", failedToken); + } } } diff --git a/src/main/java/com/depromeet/stonebed/global/common/constants/NotificationConstants.java b/src/main/java/com/depromeet/stonebed/global/common/constants/NotificationConstants.java new file mode 100644 index 0000000..185e457 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/global/common/constants/NotificationConstants.java @@ -0,0 +1,12 @@ +package com.depromeet.stonebed.global.common.constants; + +import java.time.format.DateTimeFormatter; + +public final class NotificationConstants { + public static final int SQS_BATCH_SIZE = 10; + public static final long FIRST_BOOST_THRESHOLD = 1; + public static final long POPULAR_THRESHOLD = 1000; + public static final long SUPER_POPULAR_THRESHOLD = 5000; + public static final DateTimeFormatter DATE_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); +}