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 @@ -17,6 +17,7 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
* 알림 타입별 템플릿을 관리하고 발행하는 서비스
Expand Down Expand Up @@ -143,6 +144,7 @@ public void sendSystemNotification(Long targetUserId, String title, String conte
/**
* 모든 활성 사용자에게 공지사항 알림을 발송합니다.
* 사용자별 알림 설정을 확인하여 알림을 받을 사용자에게만 전송합니다.
* 배치 처리로 스레드 풀 포화를 방지합니다.
*/
public void sendNoticeNotificationToAllUsers(String noticeTitle, String noticeContent, Long noticeId) {
try {
Expand All @@ -153,25 +155,46 @@ public void sendNoticeNotificationToAllUsers(String noticeTitle, String noticeCo

int sentCount = 0;
int skippedCount = 0;

for (User user : activeUsers) {
try {
if (shouldSendNoticeNotification(user)) {
sendNoticeNotification(
user.getId(),
noticeTitle,
noticeContent,
noticeId
);
sentCount++;
} else {
final int BATCH_SIZE = 20; // 배치 크기 설정 (스레드 풀 용량 35개 고려)
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions thread pool capacity of 35, but the AsyncConfig shows maxPoolSize=10 and queueCapacity=25 (total capacity of 35). However, this is misleading since the queue only holds pending tasks, not active threads. The actual concurrent execution capacity is 10 threads. Consider clarifying this as '스레드 풀 총 용량 35개 (최대 스레드 10개 + 큐 25개) 고려' to accurately reflect the distinction between thread capacity and queue capacity.

Suggested change
final int BATCH_SIZE = 20; // 배치 크기 설정 (스레드 풀 용량 35개 고려)
final int BATCH_SIZE = 20; // 배치 크기 설정 (스레드 풀 용량 35개 [최대 스레드 10개 + 큐 25개] 고려)

Copilot uses AI. Check for mistakes.

for (int i = 0; i < activeUsers.size(); i += BATCH_SIZE) {
int endIndex = Math.min(i + BATCH_SIZE, activeUsers.size());
List<User> batch = activeUsers.subList(i, endIndex);

log.debug("배치 처리 중: {}/{} (배치 크기: {})",
endIndex, activeUsers.size(), batch.size());

/// 푸시 알림 전송
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This comment uses triple slashes (///) which is inconsistent with the double slash (//) comment style used elsewhere in the same method (lines 189). The codebase consistently uses triple slashes for section markers and field documentation. For inline section comments within methods, consider using double slashes for consistency, or establish a clear convention.

Copilot uses AI. Check for mistakes.
for (User user : batch) {
try {
if (shouldSendNoticeNotification(user)) {
sendNoticeNotification(
user.getId(),
noticeTitle,
noticeContent,
noticeId
);
sentCount++;
} else {
skippedCount++;
log.debug("알림 설정으로 인해 푸시 전송 스킵 - 사용자 ID: {}", user.getId());
}
} catch (Exception e) {
log.error("사용자 {}에게 공지사항 푸시 알림 전송 실패: {}",
user.getId(), e.getMessage(), e);
skippedCount++;
log.debug("알림 설정으로 인해 푸시 전송 스킵 - 사용자 ID: {}", user.getId());
}
} catch (Exception e) {
log.error("사용자 {}에게 공지사항 푸시 알림 전송 실패: {}",
user.getId(), e.getMessage(), e);
skippedCount++;
}

/// 배치 간 대기 (스레드 풀 여유 확보)
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This comment uses triple slashes (///) which is inconsistent with the single-line comment style used in line 167 of the same method. The codebase consistently uses triple slashes for section markers and field documentation. For inline section comments within methods, consider using double slashes for consistency, or establish a clear convention.

Copilot uses AI. Check for mistakes.
if (endIndex < activeUsers.size()) {
try {
TimeUnit.MILLISECONDS.sleep(100);
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded 100ms sleep duration should be extracted as a named constant (e.g., BATCH_DELAY_MILLIS) to improve maintainability and make the purpose clearer. This would also make it easier to tune the delay if needed.

Copilot uses AI. Check for mistakes.
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("배치 처리 중 인터럽트 발생");
break;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ public void onFailure(Throwable throwable) {
log.error("FCM 알림 전송 실패: {}, 에러: {}",
notification.getId(), e.getMessage());
}

// 실패한 알림도 전송 완료로 표시하여 재시도 방지
notification.markAsSent();
updatedNotifications.add(notification);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public Executor taskExecutor() {
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("PushNotification-");
executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
Expand Down
Loading