난수 생성 문제로 풀링 제거 원복 및 큐 사용 비동기처리.

This commit is contained in:
cho
2026-03-05 14:48:37 +09:00
parent 7ac995e5ef
commit 4f5fa96ef5
2 changed files with 140 additions and 126 deletions
@@ -18,6 +18,7 @@ import com.eactive.eai.custom.alarm.event.AlarmEvent;
import com.eactive.eai.custom.alarm.key.AlarmKey; import com.eactive.eai.custom.alarm.key.AlarmKey;
import com.eactive.eai.custom.alarm.policy.AlarmPolicy; import com.eactive.eai.custom.alarm.policy.AlarmPolicy;
import com.eactive.eai.custom.alarm.policy.SendPolicy; import com.eactive.eai.custom.alarm.policy.SendPolicy;
import com.eactive.eai.custom.alarm.ums.UmsSendManager;
import com.eactive.eai.custom.alarm.ums.UmsService; import com.eactive.eai.custom.alarm.ums.UmsService;
import com.eactive.eai.custom.alarm.ums.payload.ObpMonitoringUmsTemplate; import com.eactive.eai.custom.alarm.ums.payload.ObpMonitoringUmsTemplate;
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload; import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
@@ -37,7 +38,7 @@ public class AlarmStateManager {
AlarmService alarmService; AlarmService alarmService;
@Autowired @Autowired
UmsService usmService; UmsSendManager umsSendManager;
public static AlarmStateManager getAlarmStateManager() { public static AlarmStateManager getAlarmStateManager() {
if (alarmStateManager == null) { if (alarmStateManager == null) {
@@ -104,14 +105,13 @@ public class AlarmStateManager {
} }
// 리스트에서 안전하게 제거 // 리스트에서 안전하게 제거
iterator.remove(); iterator.remove();
}else { //트리거 조건이 안되더라도, 이벤트발생한지 오래 되었으면 제거하여 OOM 예방. } else { // 트리거 조건이 안되더라도, 이벤트발생한지 오래 되었으면 제거하여 OOM 예방.
long firstOcurredAt = event.getCondition().getOcurredAt(); long firstOcurredAt = event.getCondition().getOcurredAt();
long diffInMs = System.currentTimeMillis() - firstOcurredAt; long diffInMs = System.currentTimeMillis() - firstOcurredAt;
if ( diffInMs >= TimeUnit.MINUTES.toMillis(60) ) { //1시간 지난거면 삭제 if (diffInMs >= TimeUnit.MINUTES.toMillis(60)) { // 1시간 지난거면 삭제
iterator.remove(); iterator.remove();
} }
} }
@@ -133,7 +133,8 @@ public class AlarmStateManager {
.content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build()) .content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build())
.cellphone(cellPhone).build(); .cellphone(cellPhone).build();
logger.info("Alarm is disabled, UmsRequestPayload = {}", payload); logger.info("Alarm is disabled, UmsRequestPayload = {}", payload);
usmService.send(payload);
umsSendManager.enqueue(payload);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -3,10 +3,13 @@ package com.eactive.eai.custom.alarm.ums;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -16,11 +19,13 @@ import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
@Component @Component
public class UmsSendManager { public class UmsSendManager {
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
// 1. I/O 처리를 위한 전용 스레드 풀 (예: 최대 10개 스레드)
private final ExecutorService ioExecutor = Executors.newFixedThreadPool(10);
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); // 2. 메모리 보호를 위해 크기 제한이 있는 큐 권장 (선택사항)
private final Queue<UmsRequestPayload> queue = new ConcurrentLinkedQueue<>();
Queue<UmsRequestPayload> queue = new ConcurrentLinkedQueue<UmsRequestPayload>();
@Autowired @Autowired
UmsService umsService; UmsService umsService;
@@ -28,46 +33,54 @@ public class UmsSendManager {
public UmsSendManager() { public UmsSendManager() {
this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r); Thread t = new Thread(r);
t.setName("AlarmStateManager-worker"); t.setName("UmsSendManager-worker");
t.setDaemon(false);
return t; return t;
}); });
scheduler.scheduleWithFixedDelay(() -> { scheduler.scheduleWithFixedDelay(() -> {
try { try {
// === 여기에 지속 실행할 로직 ===
sendMessage(); sendMessage();
} catch (Throwable e) { } catch (Throwable e) {
// 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음) logger.error("UMS 스케줄러 실행 중 오류", e);
logger.error("fireAlarm fail", e); }
}, 0, 30, TimeUnit.SECONDS);
} }
}, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격 void sendMessage() {
}
void sendMessage() throws Exception {
UmsRequestPayload payload; UmsRequestPayload payload;
while ((payload = queue.poll()) != null) { // 3. 한 번의 주기당 최대 처리량 제한 (필요시)
int count = 0;
while ((payload = queue.poll()) != null && count < 1000) {
final UmsRequestPayload finalPayload = payload; final UmsRequestPayload finalPayload = payload;
// 전용 Executor를 사용하여 공용 풀 보호
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
UmsCallResult result = null;
try { try {
result = umsService.send(finalPayload); umsService.send(finalPayload);
} catch (Exception e) { } catch (Exception e) {
logger.error("UMS 전송 실패", e); logger.error("UMS 전송 실패", e);
}finally {
logger.info(result);
} }
}); }, ioExecutor);
count++;
}
} }
// 4. 안전한 종료 처리
@PreDestroy
public void stop() {
scheduler.shutdown();
ioExecutor.shutdown();
try {
if (!ioExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
ioExecutor.shutdownNow();
}
} catch (InterruptedException e) {
ioExecutor.shutdownNow();
logger.error("UmsSendManager shutdownNow.", e);
}
} }
public void enqueue(UmsRequestPayload payload) { public void enqueue(UmsRequestPayload payload) {
queue.offer(payload); queue.offer(payload);
} }
} }