From 0340f63a799d3a81071b73a3495a707b7d0cc474 Mon Sep 17 00:00:00 2001 From: cho Date: Fri, 6 Feb 2026 09:43:58 +0900 Subject: [PATCH] =?UTF-8?q?ums=20Alarm=20=EC=9E=91=EC=97=85..?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eactive/eai/common/util/Jsons.java | 10 +++ .../eai/custom/alarm/AlarmService.java | 80 ++++++++++++++++++ .../eai/custom/alarm/AlarmStateManager.java | 78 +++++++++++++++++ .../alarm/condition/AlarmCondition.java | 19 +++++ .../custom/alarm/condition/AlarmLevel.java | 5 ++ .../eai/custom/alarm/event/AlarmEvent.java | 37 +++++++++ .../eai/custom/alarm/key/AlarmKey.java | 5 ++ .../eai/custom/alarm/key/CoreAlarmKey.java | 9 ++ .../eai/custom/alarm/key/DynamicAlarmKey.java | 30 +++++++ .../eai/custom/alarm/policy/AlarmPolicy.java | 83 +++++++++++++++++++ .../eai/custom/alarm/policy/AlarmType.java | 5 ++ .../custom/alarm/policy/CounterPolicy.java | 39 +++++++++ .../eai/custom/alarm/policy/TimerPolicy.java | 52 ++++++++++++ 13 files changed, 452 insertions(+) create mode 100644 src/main/java/com/eactive/eai/common/util/Jsons.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/AlarmService.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java create mode 100644 src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java diff --git a/src/main/java/com/eactive/eai/common/util/Jsons.java b/src/main/java/com/eactive/eai/common/util/Jsons.java new file mode 100644 index 0000000..a9379f4 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/util/Jsons.java @@ -0,0 +1,10 @@ +package com.eactive.eai.common.util; + +import com.google.gson.Gson; + +public final class Jsons { + + private Jsons() {} + + public static final Gson GSON = new Gson(); +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java b/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java new file mode 100644 index 0000000..6f28796 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java @@ -0,0 +1,80 @@ +package com.eactive.eai.custom.alarm; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Properties; + +import org.springframework.stereotype.Service; + +import com.eactive.eai.common.property.PropManager; +import com.eactive.eai.common.util.Jsons; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.key.DynamicAlarmKey; +import com.eactive.eai.custom.alarm.policy.AlarmPolicy; +import com.eactive.eai.custom.alarm.policy.CounterPolicy; +import com.eactive.eai.custom.alarm.policy.TimerPolicy; +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +@Service +public class AlarmService { + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + final static String ALARM_GROUP = "Alarm"; + final static String ALARM_KEY = "Alarm"; + final static String ALARM_RECIVER = "{RECIVER}"; + + public List getAlarmPolicy() { + + List policyList = new ArrayList(); + + try { + + Properties props = PropManager.getInstance().getProperties(ALARM_GROUP); + + props.forEach((key, value) -> { + String keyName = (String) key; + String configStr = (String) value; + + if (keyName.contains(ALARM_RECIVER)) + return; + + policyList.add(buildAlarmPolicy(keyName, configStr)); + + }); + + } catch (Exception e) { + logger.error("getAlarmPolicy fail.", e); + return Collections.EMPTY_LIST; + } + + return null; + } + + AlarmPolicy buildAlarmPolicy(String key, String configJsonStr) { + + JsonObject alarmConfig = Jsons.GSON.fromJson(configJsonStr, JsonObject.class); + + String policyType = alarmConfig.get("type").getAsString(); + int coolDownSec = Optional.ofNullable(alarmConfig.get("coolDownSec")).map(i -> i.getAsInt()).orElse(60); + int thresholdCount = Optional.ofNullable(alarmConfig.get("thresholdCount")).map(i -> i.getAsInt()).orElse(5); + int timeWindowSec = Optional.ofNullable(alarmConfig.get("timeWindowSec")).map(i -> i.getAsInt()).orElse(60); + + AlarmPolicy alarmPolicy; + + if ("CountPolicy".equals(policyType)) { + alarmPolicy = CounterPolicy.builder().alarmKey(new DynamicAlarmKey(key)).coolDownMs(coolDownSec * 1000) + .thresholdCount(thresholdCount).build(); + } else { + alarmPolicy = TimerPolicy.builder().alarmKey(new DynamicAlarmKey(key)).coolDownMs(coolDownSec * 1000) + .timeWindowMs(timeWindowSec * 1000).build(); + } + + return alarmPolicy; + + } +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java b/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java new file mode 100644 index 0000000..8d4bfd8 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java @@ -0,0 +1,78 @@ +package com.eactive.eai.custom.alarm; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Component; + +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.event.AlarmEvent; + +@Component +public class AlarmStateManager { + + + List registerAlarmList = new ArrayList(); + + private final ScheduledExecutorService scheduler; + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + + public AlarmStateManager() { + + this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r); + t.setName("AlarmStateManager-worker"); + t.setDaemon(false); + return t; + }); + + scheduler.scheduleWithFixedDelay(() -> { + + try { + // === 여기에 지속 실행할 로직 === + fireAlarm(); + + } catch (Throwable e) { + // 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음) + logger.error("fireAlarm fail", e); + } + + }, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격 + } + + + public void onEvnet(AlarmEvent alaramEvent) { + + Optional existEvent = + registerAlarmList.stream() + .filter(e -> e.equals(alaramEvent)) + .findFirst(); + + if (existEvent.isPresent()) { + AlarmEvent event = existEvent.get(); + event.onOcurr(); + } else { + registerAlarmList.add(alaramEvent); + } + + } + + private void fireAlarm() { + + for(AlarmEvent event : registerAlarmList) { + + + + } + + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java new file mode 100644 index 0000000..7d852f4 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java @@ -0,0 +1,19 @@ +package com.eactive.eai.custom.alarm.condition; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class AlarmCondition { + AlarmLevel level; + final long ocurredAt; + long lastOcurredAt; + long count = 1; + + public void onOcurr() { + this.lastOcurredAt = System.currentTimeMillis(); + this.count++; + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java new file mode 100644 index 0000000..f88986a --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java @@ -0,0 +1,5 @@ +package com.eactive.eai.custom.alarm.condition; + +public enum AlarmLevel { + ERROR, WARN, FATAL +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java b/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java new file mode 100644 index 0000000..1d29a3f --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java @@ -0,0 +1,37 @@ +package com.eactive.eai.custom.alarm.event; + +import java.util.Objects; + +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.key.AlarmKey; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@Builder +public class AlarmEvent { + AlarmKey key; + AlarmCondition condition; + String message; + + public void onOcurr() { + condition.onOcurr(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AlarmEvent)) return false; + + AlarmEvent that = (AlarmEvent) o; + return Objects.equals(this.key, that.key); + } + + @Override + public int hashCode() { + return Objects.hash(key); + } +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java new file mode 100644 index 0000000..c81778a --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java @@ -0,0 +1,5 @@ +package com.eactive.eai.custom.alarm.key; + +public interface AlarmKey { + String code(); +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java new file mode 100644 index 0000000..eae718b --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java @@ -0,0 +1,9 @@ +package com.eactive.eai.custom.alarm.key; +public enum CoreAlarmKey implements AlarmKey { + CircuitBreaker; + + @Override + public String code() { + return name(); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java new file mode 100644 index 0000000..c26298b --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java @@ -0,0 +1,30 @@ +package com.eactive.eai.custom.alarm.key; + +public final class DynamicAlarmKey implements AlarmKey { + + private final String code; + + public DynamicAlarmKey(String code) { + if (code == null || code.isEmpty()) { + throw new IllegalArgumentException("AlarmKey code must not be empty"); + } + this.code = code; + } + + @Override + public String code() { + return code; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AlarmKey)) return false; + return code.equals(((AlarmKey) o).code()); + } + + @Override + public int hashCode() { + return code.hashCode(); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java new file mode 100644 index 0000000..2f42186 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java @@ -0,0 +1,83 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.AlarmKey; + +public abstract class AlarmPolicy { + + private AlarmKey alarmKey; + + private int thresholdCount; + + private long timeWindowMs; + + private long coolDownMs; + + protected AlarmPolicy(Builder builder) { + this.alarmKey = builder.alarmKey; + this.thresholdCount = builder.thresholdCount; + this.timeWindowMs = builder.timeWindowMs; + this.coolDownMs = builder.coolDownMs; + } + + public AlarmKey getAlarmKey() { + return alarmKey; + } + + public int getThresholdCount() { + return thresholdCount; + } + + public long getTimeWindowMs() { + return timeWindowMs; + } + + public long getCoolDownMs() { + return coolDownMs; + } + + abstract boolean isAlarmTriggered(AlarmEvent event); + + public boolean hasElapsed(long baseTimeMs, long currentTimeMs) { + + return currentTimeMs - baseTimeMs >= timeWindowMs; + + } + + public boolean hasExceededLimit(long count) { + return count >= thresholdCount; + } + + public abstract static class Builder> { + + private AlarmKey alarmKey; + private int thresholdCount; + private long timeWindowMs; + private long coolDownMs; + + public T alarmKey(AlarmKey alarmKey) { + this.alarmKey = alarmKey; + return self(); + } + + public T thresholdCount(int thresholdCount) { + this.thresholdCount = thresholdCount; + return self(); + } + + public T timeWindowMs(long timeWindowMs) { + this.timeWindowMs = timeWindowMs; + return self(); + } + + public T coolDownMs(long coolDownMs) { + this.coolDownMs = coolDownMs; + return self(); + } + + protected abstract T self(); + + abstract AlarmPolicy build(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java new file mode 100644 index 0000000..547eaf2 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java @@ -0,0 +1,5 @@ +package com.eactive.eai.custom.alarm.policy; + +public enum AlarmType { + COUNT, TIMER +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java new file mode 100644 index 0000000..97f763d --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java @@ -0,0 +1,39 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.event.AlarmEvent; + +public class CounterPolicy extends AlarmPolicy { + + private CounterPolicy(Builder builder) { + super(builder); + } + + @Override + boolean isAlarmTriggered(AlarmEvent event) { + + if (!event.equals(getAlarmKey())) { + return false; + } + + long count = event.getCondition().getCount(); + return hasExceededLimit(count); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AlarmPolicy.Builder { + + @Override + protected Builder self() { + return this; + } + + @Override + public CounterPolicy build() { + return new CounterPolicy(this); + } + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java new file mode 100644 index 0000000..b56dde7 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java @@ -0,0 +1,52 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.policy.CounterPolicy.Builder; + +public class TimerPolicy extends AlarmPolicy { + + private TimerPolicy(Builder builder) { + super(builder); + } + + @Override + boolean isAlarmTriggered(AlarmEvent event) { + + if (event.equals(getAlarmKey())) { + + AlarmCondition condition = event.getCondition(); + + long baseTimeMs = condition.getOcurredAt(); + long lastTimeMs = condition.getLastOcurredAt(); + + if (hasElapsed(baseTimeMs, lastTimeMs)) { + return true; + } else { + return false; + } + + } + + return false; + + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AlarmPolicy.Builder { + + @Override + protected Builder self() { + return this; + } + + @Override + public TimerPolicy build() { + return new TimerPolicy(this); + } + } + +}