diff --git a/src/main/java/com/eactive/eai/agent/circuitBreaker/type/ReloadTypedCircuitBreakerCommand.java b/src/main/java/com/eactive/eai/agent/circuitBreaker/type/ReloadTypedCircuitBreakerCommand.java new file mode 100644 index 0000000..8e7cd86 --- /dev/null +++ b/src/main/java/com/eactive/eai/agent/circuitBreaker/type/ReloadTypedCircuitBreakerCommand.java @@ -0,0 +1,61 @@ +package com.eactive.eai.agent.circuitBreaker.type; + +import com.eactive.eai.agent.command.Command; +import com.eactive.eai.agent.command.CommandException; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.common.circuitBreaker.type.TypedCircuitBreakerManager; + +public class ReloadTypedCircuitBreakerCommand extends Command { + private static final long serialVersionUID = 1L; + + public ReloadTypedCircuitBreakerCommand() { + super("ReloadInflowInterfaceControlCommand"); + } + + public Object execute() throws CommandException { + Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + if (logger.isInfo()) { + logger.info(this.name + " is executed"); + } + + String keyName; + if (!(this.args instanceof String)) { + keyName = "RECEAIMCM001"; + String msg = this.makeException(keyName, (Throwable) null); + if (logger.isError()) { + logger.error(msg); + } + + throw new CommandException(msg); + } else { + keyName = (String) this.args; + + try { + TypedCircuitBreakerManager manager = TypedCircuitBreakerManager.getInstance(); + if (keyName != null) { + if ("ALL".equals(keyName)) { + manager.reload(); + if (logger.isWarn()) { + logger.warn(this.name + "] all rule Reload."); + } + } else { + manager.reload(keyName); + if (logger.isWarn()) { + logger.warn(this.name + "] " + keyName + " Reload."); + } + } + } + + return "success"; + } catch (Exception var6) { + String rspErrorCode = "RECEAIMCM002"; + String msg = this.makeException(rspErrorCode, var6); + if (logger.isError()) { + logger.error(msg, var6); + } + + throw new CommandException(msg); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerDAO.java b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerDAO.java new file mode 100644 index 0000000..e465655 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerDAO.java @@ -0,0 +1,66 @@ +package com.eactive.eai.common.circuitBreaker.type; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.eactive.eai.common.circuitbreak.loader.CircuitBreakerConfigLoader; +import com.eactive.eai.common.dao.BaseDAO; +import com.eactive.eai.common.dao.DAOException; +import com.eactive.eai.common.exception.ExceptionUtil; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; + +@Service +@Transactional +public class TypedCircuitBreakerDAO extends BaseDAO { + private static Logger logger; + @Autowired + private CircuitBreakerConfigLoader loader; + @Autowired + private TypedCircuitBreakerMapper mapper; + + public List getList() throws DAOException { + try { + Iterable rows = this.loader.findAll(); + List result = new ArrayList<>(); + logger.info("[ @@ Load UrlCircuitBreaker Configuration - starting >>>>>>>>>>>>>>>>> ]"); + for ( CircuitBreakerConfig row : rows ) { + result.add(this.mapper.toVo(row)); + } + + logger.info("[>> Load UrlCircuitBreaker Configuration - ended ]"); + return result; + } catch (Exception var5) { + throw new DAOException(ExceptionUtil.getErrorCode(var5, "RECEAICMM101")); + } + } + + public TypedCircuitBreakerVO get(String key) throws DAOException { + TypedCircuitBreakerVO var3; + try { + logger.info("[ @@ Load UrlCircuitBreaker Configuration - starting >>>>>>>>>>>>>>>>> " + key + "]"); + Optional optionalRow = this.loader.findById(key); + if (!optionalRow.isPresent()) { + var3 = null; + return var3; + } + + var3 = this.mapper.toVo((CircuitBreakerConfig) optionalRow.get()); + } catch (Exception var7) { + throw new DAOException(ExceptionUtil.getErrorCode(var7, "RECEAICMM101")); + } finally { + logger.info("[>> Load UrlCircuitBreaker Configuration - ended " + key + "]"); + } + + return var3; + } + + static { + logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerManager.java b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerManager.java new file mode 100644 index 0000000..c6622ce --- /dev/null +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerManager.java @@ -0,0 +1,562 @@ +package com.eactive.eai.common.circuitBreaker.type; + +import java.time.Duration; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.eactive.eai.common.exception.ExceptionUtil; +import com.eactive.eai.common.lifecycle.Lifecycle; +import com.eactive.eai.common.lifecycle.LifecycleException; +import com.eactive.eai.common.lifecycle.LifecycleListener; +import com.eactive.eai.common.lifecycle.LifecycleSupport; +import com.eactive.eai.common.property.PropManager; +import com.eactive.eai.common.util.ApplicationContextProvider; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.AlarmStateManager; +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.CoreAlarmKey; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.SlidingWindowType; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; +import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent; +import io.github.resilience4j.circuitbreaker.event.CircuitBreakerOnStateTransitionEvent; +import io.github.resilience4j.core.EventConsumer; +import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics; +import io.micrometer.prometheus.PrometheusConfig; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.vavr.collection.Seq; + +@Component +public class TypedCircuitBreakerManager implements Lifecycle { + static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + private static final String DEFAULT_CIRCUITBREAKER_NAME = "default"; + PrometheusMeterRegistry meterRegistry; + CircuitBreakerRegistry circuitBreakerRegistry; + TypedCircuitBreakerVO defaultConfigVo; + HashMap apiIdCBConfigMap = new HashMap<>(); + HashMap urlCBConfigMap = new HashMap<>(); + private boolean started; + + @Autowired + private TypedCircuitBreakerDAO dao; + private LifecycleSupport lifecycle = new LifecycleSupport(this); + + public static synchronized TypedCircuitBreakerManager getInstance() { + return (TypedCircuitBreakerManager) ApplicationContextProvider.getContext() + .getBean(TypedCircuitBreakerManager.class); + } + + public void addLifecycleListener(LifecycleListener listener) { + this.lifecycle.addLifecycleListener(listener); + } + + public LifecycleListener[] findLifecycleListeners() { + return this.lifecycle.findLifecycleListeners(); + } + + public void removeLifecycleListener(LifecycleListener listener) { + this.lifecycle.removeLifecycleListener(listener); + } + + private void init() throws Exception { + this.meterRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + int failureRateThreshold = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "failureRateThreshold"), 50); + int slidingWindowSize = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "slidingWindowSize"), 100); + int minimumNumberOfCalls = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "minimumNumberOfCalls"), 100); + int waitDurationInOpenState = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "waitDurationInOpenState"), 60); + int permittedNumberOfCallsInHalfOpenState = NumberUtils.toInt( + PropManager.getInstance().getProperty("CircuitBreaker", "permittedNumberOfCallsInHalfOpenState"), 10); + int slowCallRateThreshold = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "slowCallRateThreshold"), 100); + int slowCallDurationThreshold = NumberUtils + .toInt(PropManager.getInstance().getProperty("CircuitBreaker", "slowCallDurationThreshold"), 5); + String useYn = PropManager.getInstance().getProperty("CircuitBreaker", "useYn", "N"); + useYn = normalizeUseYn(useYn); + + CircuitBreakerConfig defaultConfig = CircuitBreakerConfig.custom() + .failureRateThreshold((float) failureRateThreshold).slidingWindowSize(slidingWindowSize) + .minimumNumberOfCalls(minimumNumberOfCalls) + .waitDurationInOpenState(Duration.ofSeconds((long) waitDurationInOpenState)) + .permittedNumberOfCallsInHalfOpenState(permittedNumberOfCallsInHalfOpenState) + .slidingWindowType(SlidingWindowType.COUNT_BASED).slowCallRateThreshold((float) slowCallRateThreshold) + .slowCallDurationThreshold(Duration.ofSeconds((long) slowCallDurationThreshold)).build(); + this.defaultConfigVo = TypedCircuitBreakerVO.builder().name(DEFAULT_CIRCUITBREAKER_NAME).failureRateThreshold(failureRateThreshold) + .slidingWindowSize(slidingWindowSize).minimumNumberOfCalls(minimumNumberOfCalls) + .waitDurationInOpenState(waitDurationInOpenState) + .permittedNumberOfCallsInHalfOpenState(permittedNumberOfCallsInHalfOpenState) + .slowCallRateThreshold(slowCallRateThreshold).slowCallDurationThreshold(slowCallDurationThreshold) + .useYn(useYn).circuitBreakerConfig(defaultConfig).build(); + this.circuitBreakerRegistry = CircuitBreakerRegistry.of(defaultConfig); + CircuitBreakerConfig defaultCircuitBreakerConfig = this.createCircuitBreakerConfig(this.defaultConfigVo); + this.defaultConfigVo.setCircuitBreakerConfig(defaultCircuitBreakerConfig); + this.apiIdCBConfigMap.put(DEFAULT_CIRCUITBREAKER_NAME, this.defaultConfigVo); + List circuitBreakerList = this.dao.getList(); + + for (TypedCircuitBreakerVO vo : circuitBreakerList) { + if (!StringUtils.equalsIgnoreCase(vo.useYn, "1")) { + this.apiIdCBConfigMap.remove(vo.getName()); + logger.info("init skip (useYn) - " + vo); + } else { + CircuitBreakerConfig circuitBreakerConfig = this.createCircuitBreakerConfig(vo); + vo.setCircuitBreakerConfig(circuitBreakerConfig); + this.apiIdCBConfigMap.put(vo.getName(), vo); + } + } + + logger.info("init map - " + this.apiIdCBConfigMap); + TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(this.circuitBreakerRegistry).bindTo(this.meterRegistry); + logger.info("init default - " + this.defaultConfigVo); + for (TypedCircuitBreakerVO vo : circuitBreakerList) { + CircuitBreaker cbreaker = this.getCircuitBreaker(vo.getName()); + this.printCircuitBreakerInfo(vo.getName(), cbreaker); + } + + CircuitBreaker cbreaker = this.getCircuitBreaker(DEFAULT_CIRCUITBREAKER_NAME); + this.printCircuitBreakerInfo(DEFAULT_CIRCUITBREAKER_NAME, cbreaker); + this.addListenerAll(); + } + + private String normalizeUseYn(String useYn) { + if(StringUtils.equalsAnyIgnoreCase(useYn, "Y", "1")) + useYn = "1";//사용 + else + useYn = "0"; + return useYn; + } + + private CircuitBreakerConfig createCircuitBreakerConfig(TypedCircuitBreakerVO vo) { + return CircuitBreakerConfig.custom().failureRateThreshold((float) vo.failureRateThreshold) + .slidingWindowSize(vo.slidingWindowSize).minimumNumberOfCalls(vo.minimumNumberOfCalls) + .waitDurationInOpenState(Duration.ofSeconds((long) vo.waitDurationInOpenState)) + .permittedNumberOfCallsInHalfOpenState(vo.permittedNumberOfCallsInHalfOpenState) + .slidingWindowType(SlidingWindowType.COUNT_BASED) + .slowCallRateThreshold((float) vo.slowCallRateThreshold) + .slowCallDurationThreshold(Duration.ofSeconds((long) vo.slowCallDurationThreshold)).build(); + } + + public void reload() throws Exception { + this.init(); + } + + @SuppressWarnings("deprecation") + public void reload(String key) throws Exception { + logger.info("reload start."); + TypedCircuitBreakerVO vo = this.dao.get(key); + if (StringUtils.equalsIgnoreCase(vo.useYn, "0")) { + this.apiIdCBConfigMap.remove(vo.getName()); + this.circuitBreakerRegistry.remove(vo.getName()); + logger.info("removed. - " + vo); + } else { + CircuitBreakerConfig circuitBreakerConfig = this.createCircuitBreakerConfig(vo); + vo.setCircuitBreakerConfig(circuitBreakerConfig); + this.apiIdCBConfigMap.put(vo.getName(), vo); + CircuitBreaker oldBreaker = this.circuitBreakerRegistry.circuitBreaker(vo.getName()); + if(oldBreaker != null) + logger.info("oldBreaker={}, waitDurationInOpenState={}", new Object[]{oldBreaker.getCircuitBreakerConfig(), + oldBreaker.getCircuitBreakerConfig().getWaitDurationInOpenState()}); + this.circuitBreakerRegistry.remove(vo.getName()); + this.circuitBreakerRegistry.circuitBreaker(vo.getName(), vo.getCircuitBreakerConfig()); + this.addListener(vo.getName()); + CircuitBreaker newBreaker = this.circuitBreakerRegistry.circuitBreaker(vo.getName()); + logger.info("newBreaker={}, waitDurationInOpenState={}", new Object[]{newBreaker.getCircuitBreakerConfig(), + newBreaker.getCircuitBreakerConfig().getWaitDurationInOpenState()}); + logger.info("reload end." + vo); + } + } + + public PrometheusMeterRegistry getMeterRegistry() { + return this.meterRegistry; + } + + public void start() throws LifecycleException { + this.lifecycle.fireLifecycleEvent("starting", this); + + try { + this.init(); + } catch (Exception var2) { + throw new LifecycleException(ExceptionUtil.getErrorCode(var2, "RECEAICMM202")); + } + + this.started = true; + this.lifecycle.fireLifecycleEvent("started", this); + } + + public void stop() throws LifecycleException { + if (!this.started) { + throw new LifecycleException("RECEAICRT203"); + } else { + this.lifecycle.fireLifecycleEvent("stoping", this); + this.started = false; + this.circuitBreakerRegistry = null; + this.lifecycle.fireLifecycleEvent("stopped", this); + } + } + + public boolean isStarted() { + return this.started; + } + + public CircuitBreaker getCircuitBreaker(String apiId) { + CircuitBreaker circuitBreaker = this.getCircuitBreakerInternal(apiId); + if (circuitBreaker != null) { + return circuitBreaker; + } else { + return this.getCircuitBreakerInternal(DEFAULT_CIRCUITBREAKER_NAME); + } + } + + private CircuitBreaker getCircuitBreakerInternal(String url) { + TypedCircuitBreakerVO vo = (TypedCircuitBreakerVO) this.apiIdCBConfigMap.get(url); + if (vo == null) { + return null; + } else { + return StringUtils.equals(vo.getUseYn(), "0") + ? null + : this.circuitBreakerRegistry.circuitBreaker(url, vo.getCircuitBreakerConfig()); + } + } + +// public CircuitBreaker getUrlCircuitBreaker(String url) { +// CircuitBreaker circuitBreaker = this.getUrlCircuitBreakerInternal(url); +// if (circuitBreaker != null) { +// return circuitBreaker; +// } else { +// URI uri = null; +// +// try { +// uri = URLUtils.createURI(url); +// } catch (Exception var6) { +// logger.error("malformed url : " + url); +// return null; +// } +// +// String tmpUrl = URLUtils.getURLWithoutQuery(uri); +// circuitBreaker = this.getUrlCircuitBreakerInternal(tmpUrl); +// if (circuitBreaker != null) { +// return circuitBreaker; +// } else { +// String host = URLUtils.getHost(uri); +// circuitBreaker = this.getUrlCircuitBreakerInternal(host); +// return circuitBreaker != null ? circuitBreaker : this.getUrlCircuitBreakerInternal(DEFAULT_CIRCUITBREAKER_NAME); +// } +// } +// } +// +// private CircuitBreaker getUrlCircuitBreakerInternal(String url) { +// TypedCircuitBreakerVO vo = (TypedCircuitBreakerVO) this.urlCBConfigMap.get(url); +// if (vo == null) { +// return null; +// } else { +// return StringUtils.equals(vo.getUseYn(), "0") +// ? null +// : this.circuitBreakerRegistry.circuitBreaker(url, vo.getCircuitBreakerConfig()); +// } +// } + + public String printCircuitBreakerInfo(String prefix, CircuitBreaker circuitBreaker) { + if (circuitBreaker == null) { + logger.info("CircuitBreaker state : " + prefix + " - null"); + return "null"; + } else { + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode combinedNode = objectMapper.createObjectNode(); + combinedNode.put("state", circuitBreaker.getState().toString()); + combinedNode.put("config", circuitBreaker.getCircuitBreakerConfig().toString()); + combinedNode.set("metrics", objectMapper.valueToTree(circuitBreaker.getMetrics())); + logger.info("CircuitBreaker state : " + prefix + " - " + combinedNode.toString()); + return combinedNode.toString(); + } + } + + public void addListenerAll() { + if (this.circuitBreakerRegistry != null) { + Seq circuitBreakers = this.circuitBreakerRegistry.getAllCircuitBreakers(); + for (CircuitBreaker cBreaker : circuitBreakers) { + TypedCircuitBreakerVO vo = (TypedCircuitBreakerVO) this.apiIdCBConfigMap.get(cBreaker.getName()); + cBreaker.getEventPublisher().onEvent(new CustomCircuitBreakerEventConsumer(vo)); + logger.info("Added Listener.[{}]", new Object[]{cBreaker.getName()}); + } + + logger.info("Added all Listener."); + } else { + logger.error("CircuitBreakerRegistry not initialized."); + } + + } + + public void addListener(String cBreakerName) { + if (this.circuitBreakerRegistry != null) { + CircuitBreaker cBreaker = this.circuitBreakerRegistry.circuitBreaker(cBreakerName); + if (cBreaker != null) { + TypedCircuitBreakerVO vo = (TypedCircuitBreakerVO) this.apiIdCBConfigMap.get(cBreakerName); + cBreaker.getEventPublisher().onEvent(new CustomCircuitBreakerEventConsumer(vo)); + logger.info("Added Listener."); + } else { + logger.error("CircuitBreaker[{}] not exist.", new Object[]{cBreakerName}); + } + } else { + logger.error("CircuitBreakerRegistry not initialized."); + } + + } + + public static class CustomCircuitBreakerEventConsumer implements EventConsumer { + TypedCircuitBreakerVO vo; +// private static final int MAX_THREADS = 5; +// private static final ExecutorService ALERT_EXECUTOR; + + public CustomCircuitBreakerEventConsumer(TypedCircuitBreakerVO vo) { + this.vo = vo; + } + + public void consumeEvent(CircuitBreakerEvent event) { + switch (event.getEventType()) { + case ERROR : + TypedCircuitBreakerManager.logger + .error("CirbuitBreaker ERROR event occurred. CircuitBreakerEvent={}" + event); + break; + case STATE_TRANSITION : + if (event instanceof CircuitBreakerOnStateTransitionEvent) { + CircuitBreakerOnStateTransitionEvent stateTransitionEvent = (CircuitBreakerOnStateTransitionEvent) event; + CircuitBreaker.StateTransition stateTransition = stateTransitionEvent.getStateTransition(); + CircuitBreaker.State toState = stateTransition.getToState(); + CircuitBreaker.State fromState = stateTransition.getFromState(); + TypedCircuitBreakerManager.logger.error( + "CirbuitBreaker STATE_TRANSITION event occurred. {} : {} -> {}. CircuitBreakerEvent={}, UrlCircuitBreakerVO={}", + new Object[]{event.getCircuitBreakerName(), fromState, toState, event, this.vo}); +// if (!toState.equals(State.OPEN) && !toState.equals(State.HALF_OPEN) +// && !toState.equals(State.CLOSED)) { +// TypedCircuitBreakerManager.logger.debug( +// "CirbuitBreaker STATE_TRANSITION event alert 대상 아님. CircuitBreakerEvent={}, UrlCircuitBreakerVO={}", +// new Object[]{event, this.vo}); +// } else { +// this.sendAlert(stateTransitionEvent); +// } + AlarmEvent alarmEvent = AlarmEvent.builder().key(CoreAlarmKey.CircuitBreaker) + .condition(AlarmCondition.builder().build()) + .message(String.format("CircuitBreaker state changed. apiId=%s, %s -> %s", event.getCircuitBreakerName(), fromState, toState)) + .build(); + + AlarmStateManager.getAlarmStateManager().onEvnet(alarmEvent); + + logger.warn("CircuitBreaker state changed. apiId={}, {} -> {}", event.getCircuitBreakerName(), fromState, toState); + + } else { + TypedCircuitBreakerManager.logger.error( + "CirbuitBreaker STATE_TRANSITION event occurred. CircuitBreakerEvent={}, UrlCircuitBreakerVO={}", + new Object[]{event, this.vo}); + } + break; + + case NOT_PERMITTED : + TypedCircuitBreakerManager.logger + .warn("CirbuitBreaker NOT_PERMITTED event occurred. CircuitBreakerEvent={}" + event); + break; + default : + TypedCircuitBreakerManager.logger + .info("CirbuitBreaker event occurred. CircuitBreakerEvent={}" + event); + } + + } + +// private void sendAlert(final CircuitBreakerOnStateTransitionEvent event) { +// this.runAsync(new Runnable() { +// public void run() { +// try { +// String alertUrl = PropManager.getInstance().getProperty("CircuitBreaker", "alert.url"); +// if (StringUtils.isEmpty(alertUrl)) { +// TypedCircuitBreakerManager.logger.warn("alert skip - alertUrl not set. - {}", +// new Object[]{event}); +// return; +// } +// +// String sendEventType = PropManager.getInstance().getProperty("CircuitBreaker", +// "alert.message.send.event.type", "OPEN,HALF_OPEN,CLOSED"); +// String[] sendEventTypeArr = sendEventType.split(","); +// CircuitBreaker.StateTransition stateTransition = event.getStateTransition(); +// CircuitBreaker.State toState = stateTransition.getToState(); +// boolean bSend = false; +// String[] var7 = sendEventTypeArr; +// int var8 = sendEventTypeArr.length; +// +// for (int var9 = 0; var9 < var8; ++var9) { +// String eventType = var7[var9]; +// if (State.valueOf(eventType).equals(toState)) { +// bSend = true; +// break; +// } +// } +// +// if (bSend) { +// String json = CustomCircuitBreakerEventConsumer.this.createAlertMessage(event); +// TypedCircuitBreakerManager.logger.info("alert request - {}", new Object[]{json}); +// String result = CustomCircuitBreakerEventConsumer.this.httpPost(alertUrl, json); +// TypedCircuitBreakerManager.logger.info("alert result - {}", new Object[]{result}); +// } else { +// TypedCircuitBreakerManager.logger.info("alert 전송대상 아님 - {}", new Object[]{event}); +// } +// } catch (Exception var11) { +// TypedCircuitBreakerManager.logger.error("alert 전송 처리 실패 - {}", event, var11); +// } +// +// } +// }); +// } +// +// private void runAsync(Runnable task) { +// try { +// ALERT_EXECUTOR.execute(task); +// } catch (RejectedExecutionException var3) { +// TypedCircuitBreakerManager.logger.error("alert 작업 제출 중 예외", var3); +// } +// +// } +// +// private String createAlertMessage(CircuitBreakerOnStateTransitionEvent event) { +// String alertMessageTemplate = PropManager.getInstance().getProperty("CircuitBreaker", +// "alert.message.template", "CircuitBreaker({url},{desc}){from}->{to}"); +// String alertMsg = alertMessageTemplate.replace("{url}", this.vo.getName()); +// alertMsg = alertMsg.replace("{desc}", this.vo.getDesc() + ""); +// CircuitBreaker.StateTransition stateTransition = event.getStateTransition(); +// alertMsg = alertMsg.replace("{from}", stateTransition.getFromState() + ""); +// alertMsg = alertMsg.replace("{to}", stateTransition.getToState() + ""); +// JSONObject reqJson = new JSONObject(); +// reqJson.put("alertType", "C"); +// reqJson.put("alertMsg", alertMsg); +// return reqJson.toJSONString(); +// } +// +// private String httpPost(String url, String json) { +// String resultMsg = ""; +// StringBuilder result = new StringBuilder(); +// +// try { +// URL urlObject = new URL(url); +// HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection(); +// conn.setDoOutput(true); +// conn.setDoInput(true); +// conn.setRequestProperty("Content-Type", "application/json"); +// conn.setRequestMethod("POST"); +// OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); +// Throwable var8 = null; +// +// try { +// if (StringUtils.isNotEmpty(json)) { +// wr.write(json.toString()); +// wr.flush(); +// } +// } catch (Throwable var55) { +// var8 = var55; +// throw var55; +// } finally { +// if (wr != null) { +// if (var8 != null) { +// try { +// wr.close(); +// } catch (Throwable var54) { +// var8.addSuppressed(var54); +// } +// } else { +// wr.close(); +// } +// } +// +// } +// +// int resStatusCode = conn.getResponseCode(); +// Throwable var9; +// String line; +// BufferedReader normalBr; +// if (resStatusCode != 201 && resStatusCode != 200) { +// TypedCircuitBreakerManager.logger.debug("httpPost call response http code : {}" + resStatusCode); +// TypedCircuitBreakerManager.logger +// .debug("httpPost call response errror message : {}" + conn.getResponseMessage()); +// normalBr = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8")); +// var9 = null; +// +// try { +// line = ""; +// +// while ((line = normalBr.readLine()) != null) { +// result.append(line); +// } +// } catch (Throwable var58) { +// var9 = var58; +// throw var58; +// } finally { +// if (normalBr != null) { +// if (var9 != null) { +// try { +// normalBr.close(); +// } catch (Throwable var53) { +// var9.addSuppressed(var53); +// } +// } else { +// normalBr.close(); +// } +// } +// +// } +// } +// +// normalBr = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); +// var9 = null; +// +// try { +// line = ""; +// +// while ((line = normalBr.readLine()) != null) { +// result.append(line); +// } +// } catch (Throwable var56) { +// var9 = var56; +// throw var56; +// } finally { +// if (normalBr != null) { +// if (var9 != null) { +// try { +// normalBr.close(); +// } catch (Throwable var52) { +// var9.addSuppressed(var52); +// } +// } else { +// normalBr.close(); +// } +// } +// +// } +// +// resultMsg = result.toString(); +// } catch (Exception var61) { +// TypedCircuitBreakerManager.logger.error("url : para data => {} : {}" + url + " : " + json); +// TypedCircuitBreakerManager.logger.error("http client error : {}" + var61.getMessage(), var61); +// resultMsg = result.toString(); +// } +// +// return resultMsg; +// } +// +// static { +// ALERT_EXECUTOR = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MICROSECONDS, new SynchronousQueue(), +// Executors.defaultThreadFactory(), new RejectedExecutionHandler() { +// public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { +// TypedCircuitBreakerManager.logger.error("alert 작업 거부됨. 쓰레드 모두 사용중입니다."); +// } +// }); +// } + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerMapper.java b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerMapper.java new file mode 100644 index 0000000..ba10797 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerMapper.java @@ -0,0 +1,22 @@ +package com.eactive.eai.common.circuitBreaker.type; + +import com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; +import com.eactive.eai.data.mapper.GenericMapper; +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.ReportingPolicy; + +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface TypedCircuitBreakerMapper extends GenericMapper { + @Mappings({ + @Mapping(source = "cbreakerName", target = "name"), + @Mapping(source = "cbreakerDesc", target = "desc"), + @Mapping(source = "cbreakerType", target = "type"), + }) + TypedCircuitBreakerVO toVo(CircuitBreakerConfig var1); + + @InheritInverseConfiguration + CircuitBreakerConfig toEntity(TypedCircuitBreakerVO var1); +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerVO.java b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerVO.java new file mode 100644 index 0000000..c96a727 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/type/TypedCircuitBreakerVO.java @@ -0,0 +1,22 @@ +package com.eactive.eai.common.circuitBreaker.type; + +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TypedCircuitBreakerVO { + String type; + String name; + String desc; + int failureRateThreshold; + int slidingWindowSize; + int minimumNumberOfCalls; + int waitDurationInOpenState; + int permittedNumberOfCallsInHalfOpenState; + int slowCallRateThreshold; + int slowCallDurationThreshold; + String useYn; + CircuitBreakerConfig circuitBreakerConfig; +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/type/URLUtils.java b/src/main/java/com/eactive/eai/common/circuitBreaker/type/URLUtils.java new file mode 100644 index 0000000..1519778 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/type/URLUtils.java @@ -0,0 +1,46 @@ +package com.eactive.eai.common.circuitBreaker.type; + +import java.net.URI; + +public class URLUtils { + public static URI createURI(String uri) { + return URI.create(uri); + } + + public static String getURLWithoutQuery(URI uri) { + String result = uri.getScheme() + "://" + uri.getHost(); + if (uri.getPort() != -1) { + result = result + ":" + uri.getPort(); + } + + result = result + uri.getPath(); + return result; + } + + public static String getHost(URI uri) { + return uri.getHost(); + } + + public static void main(String[] args) throws Exception { + URI uri = URI.create("http://localhost:8001/path?query=a"); + System.out.println(uri.getHost()); + System.out.println(uri.getPath()); + System.out.println(uri.toString()); + System.out.println(uri.getRawPath()); + System.out.println(uri.toURL()); + System.out.println(getURLWithoutQuery(uri)); + System.out.println(getHost(uri)); + uri = URI.create("http://localhost/path?query=a"); + System.out.println(getURLWithoutQuery(uri)); + System.out.println(getHost(uri)); + uri = URI.create("http://localhost/path?query=a"); + System.out.println(getURLWithoutQuery(uri)); + System.out.println(getHost(uri)); + uri = URI.create("http://127.0.0.1/path?query=a"); + System.out.println(getURLWithoutQuery(uri)); + System.out.println(getHost(uri)); + uri = URI.create("http://www.example.com:8080/test/path?query=a"); + System.out.println(getURLWithoutQuery(uri)); + System.out.println(getHost(uri)); + } +} \ No newline at end of file