ums Alarm 작업..
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
@@ -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<AlarmPolicy> getAlarmPolicy() {
|
||||||
|
|
||||||
|
List<AlarmPolicy> policyList = new ArrayList<AlarmPolicy>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<AlarmEvent> registerAlarmList = new ArrayList<AlarmEvent>();
|
||||||
|
|
||||||
|
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<AlarmEvent> 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) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.condition;
|
||||||
|
|
||||||
|
public enum AlarmLevel {
|
||||||
|
ERROR, WARN, FATAL
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.key;
|
||||||
|
|
||||||
|
public interface AlarmKey {
|
||||||
|
String code();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.key;
|
||||||
|
public enum CoreAlarmKey implements AlarmKey {
|
||||||
|
CircuitBreaker;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String code() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<T extends Builder<T>> {
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
public enum AlarmType {
|
||||||
|
COUNT, TIMER
|
||||||
|
}
|
||||||
@@ -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<Builder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Builder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CounterPolicy build() {
|
||||||
|
return new CounterPolicy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<Builder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Builder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimerPolicy build() {
|
||||||
|
return new TimerPolicy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user