알림 발송 관련 배치 리네이밍
This commit is contained in:
@@ -9,15 +9,7 @@
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/applicationContext.xml</param-value>
|
||||
</context-param>
|
||||
<!-- XSS Filter -->
|
||||
<filter>
|
||||
<filter-name>CrossScriptingFilter</filter-name>
|
||||
<filter-class>com.eactive.eai.rms.common.filter.CrossScriptingFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>CrossScriptingFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
<filter>
|
||||
<filter-name>encodingFilter</filter-name>
|
||||
@@ -56,6 +48,17 @@
|
||||
<filter-name>encodingFilter</filter-name>
|
||||
<url-pattern>*.json</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
<!-- XSS Filter -->
|
||||
<filter>
|
||||
<filter-name>CrossScriptingFilter</filter-name>
|
||||
<filter-class>com.eactive.eai.rms.common.filter.CrossScriptingFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>CrossScriptingFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!--
|
||||
<filter>
|
||||
|
||||
@@ -30,12 +30,12 @@ public class ApiStatus extends AbstractEntity<String> {
|
||||
private String statusCode;
|
||||
|
||||
@LastModifiedBy // ← EMSAuditorAware가 자동으로 채움
|
||||
@Column(name = "MOD_USERID", length = 50)
|
||||
private String modUserid = "SCHEDULER";
|
||||
@Column(name = "MODIFIED_BY", length = 50)
|
||||
private String modifiedBy = "SCHEDULER";
|
||||
|
||||
@LastModifiedDate // ← save() 시 자동으로 sysdate 채움
|
||||
@Column(name = "MOD_DATE")
|
||||
private LocalDateTime modDate;
|
||||
@Column(name = "MODIFIED_DATE")
|
||||
private LocalDateTime modifiedDate;
|
||||
|
||||
@Override
|
||||
public @NonNull String getId() { return eaisvcname; }
|
||||
|
||||
@@ -2,5 +2,6 @@ package com.eactive.eai.rms.data.ext.djb.apistatus;
|
||||
|
||||
public interface ApiStatusEvent {
|
||||
String getEaisvcname();
|
||||
String getEaisvcdesc();
|
||||
String getEvent();
|
||||
}
|
||||
@@ -20,7 +20,9 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
||||
* 7. 기타 : STAY
|
||||
*/
|
||||
@Query(nativeQuery = true, value =
|
||||
" SELECT EAISVCNAME, EVENT"
|
||||
" SELECT EAISVCNAME"
|
||||
+ " , (SELECT EAISVCDESC FROM TSEAIHE01 WHERE A.EAISVCNAME = EAISVCNAME) AS EAISVCDESC"
|
||||
+ " , EVENT"
|
||||
+ " FROM ("
|
||||
+ " SELECT EAISVCNAME"
|
||||
+ " , CASE WHEN STATUS_CODE != 'C' AND CTRL_YN = 'Y' THEN 'CONTROL_START'"
|
||||
@@ -60,7 +62,7 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
||||
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI'))) AS DELAY_YN"
|
||||
+ " FROM TSEAIHE01 A LEFT OUTER JOIN API_STATUS B ON A.EAISVCNAME = B.EAISVCNAME"
|
||||
+ " )"
|
||||
+ " ) WHERE EVENT != 'STAY'")
|
||||
+ " ) A WHERE EVENT != 'STAY'")
|
||||
List<ApiStatusEvent> findApiStatusEvents(
|
||||
@Param("errorRate") int errorRate,
|
||||
@Param("errorRangeMinute") int errorRangeMinute,
|
||||
|
||||
@@ -6,9 +6,12 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.ApiStatusChangedEvent;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiStatusService {
|
||||
@@ -17,8 +20,12 @@ public class ApiStatusService {
|
||||
|
||||
@Autowired
|
||||
private ApiStatusRepository apiStatusRepository;
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
|
||||
|
||||
public void updateApiStatus(HashMap<String, String> param) {
|
||||
|
||||
List<ApiStatusEvent> list = apiStatusRepository.findApiStatusEvents(
|
||||
@@ -32,27 +39,28 @@ public class ApiStatusService {
|
||||
String newStatusCode = resolveStatusCode(event.getEvent());
|
||||
if (newStatusCode == null) continue;
|
||||
|
||||
ApiStatus apiStatus = apiStatusRepository.findById(event.getEaisvcname())
|
||||
.orElse(new ApiStatus());
|
||||
ApiStatus apiStatus = apiStatusRepository.findById(event.getEaisvcname()).orElse(new ApiStatus());
|
||||
|
||||
apiStatus.setEaisvcname(event.getEaisvcname());
|
||||
apiStatus.setStatusCode(newStatusCode);
|
||||
|
||||
apiStatusRepository.save(apiStatus); // PK 있으면 UPDATE, 없으면 INSERT
|
||||
log.debug("API 상태 변경: {} {} → {}", event.getEaisvcname(), event.getEvent(), newStatusCode);
|
||||
log.debug("API 상태 변경: {}-{} {} → {}", event.getEaisvcname(), event.getEaisvcdesc(), event.getEvent(), newStatusCode);
|
||||
|
||||
//TODO: 내부직원 알림발송 & 제휴사 webhook 발송
|
||||
eventPublisher.publishEvent(ApiStatusChangedEvent.from(event)); // 트랜잭션 커밋 후 리스너 실행
|
||||
log.debug("이벤트 전파");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String resolveStatusCode(String event) {
|
||||
switch (event) {
|
||||
case "CONTROL_START": return "C";
|
||||
case "CONTROL_END": return "N";
|
||||
case "ERROR_START": return "E";
|
||||
case "ERROR_END": return "N";
|
||||
case "DELAY_START": return "D";
|
||||
case "DELAY_END": return "N";
|
||||
case "CONTROL_START": return "C"; //점검
|
||||
case "CONTROL_END": return "N"; //정상
|
||||
case "ERROR_START": return "E"; //장애
|
||||
case "ERROR_END": return "N"; //정상
|
||||
case "DELAY_START": return "D"; //지연
|
||||
case "DELAY_END": return "N"; //정상
|
||||
default:
|
||||
log.warn("알 수 없는 이벤트: {}", event);
|
||||
return null;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class InflowTokenFailService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(InflowTokenFailService.class);
|
||||
|
||||
@Autowired
|
||||
private InflowTokenFailRepository inflowTokenFailRepository;
|
||||
|
||||
public void checkRecentFails(long rangeMinute) {
|
||||
List<InflowTokenFailSummary> rows = inflowTokenFailRepository.countByEaisvcname(rangeMinute);
|
||||
|
||||
for (InflowTokenFailSummary summary : rows) {
|
||||
log.debug("유량제어 토큰 획득 실패: {} 최근 {}분 동안 {}건", summary.getEaisvcname(), rangeMinute, summary.getCnt());
|
||||
|
||||
//TOOD: 내부직원 알림 발송
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
|
||||
public interface InflowTokenFailSummary {
|
||||
public interface InflowTokenInsufficient {
|
||||
String getEaisvcname();
|
||||
String getEaisvcdesc();
|
||||
Long getCnt();
|
||||
}
|
||||
+3
-3
@@ -17,12 +17,12 @@ import lombok.NonNull;
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true)
|
||||
@Entity
|
||||
@Table(name = "TSEAIFR11")
|
||||
public class InflowTokenFailLog extends AbstractEntity<InflowTokenFailLogId> implements Serializable {
|
||||
public class InflowTokenInsufficientLog extends AbstractEntity<InflowTokenInsufficientLogId> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@EmbeddedId
|
||||
@EqualsAndHashCode.Include
|
||||
private InflowTokenFailLogId id;
|
||||
private InflowTokenInsufficientLogId id;
|
||||
|
||||
@Column(name = "EAISEVRINSTNCNAME", length = 20)
|
||||
private String eaisevrinstncname;
|
||||
@@ -43,5 +43,5 @@ public class InflowTokenFailLog extends AbstractEntity<InflowTokenFailLogId> imp
|
||||
private String thresholdtimeunit;
|
||||
|
||||
@Override
|
||||
public @NonNull InflowTokenFailLogId getId() { return id; }
|
||||
public @NonNull InflowTokenInsufficientLogId getId() { return id; }
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
|
||||
@Data
|
||||
@Embeddable
|
||||
public class InflowTokenFailLogId implements Serializable {
|
||||
public class InflowTokenInsufficientLogId implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "EAIBZWKDSTCD", length = 4)
|
||||
+4
-3
@@ -5,13 +5,14 @@ import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
|
||||
public interface InflowTokenFailRepository extends BaseRepository<InflowTokenFailLog, InflowTokenFailLogId> {
|
||||
public interface InflowTokenRepository extends BaseRepository<InflowTokenInsufficientLog, InflowTokenInsufficientLogId> {
|
||||
|
||||
@Query(nativeQuery = true, value =
|
||||
" SELECT EAISVCNAME" +
|
||||
" , (SELECT EAISVCDESC FROM TSEAIHE01 WHERE A.EAISVCNAME = EAISVCNAME) AS EAISVCDESC" +
|
||||
" , COUNT(*) AS CNT" +
|
||||
" FROM TSEAIFR11" +
|
||||
" FROM TSEAIFR11 A" +
|
||||
" WHERE MSGDPSTYMS >= TO_CHAR(SYSTIMESTAMP - NUMTODSINTERVAL(:rangeMinute, 'MINUTE'), 'YYYYMMDDHH24MISSFF3')" +
|
||||
" GROUP BY EAISVCNAME")
|
||||
List<InflowTokenFailSummary> countByEaisvcname(@Param("rangeMinute") long rangeMinute);
|
||||
List<InflowTokenInsufficient> countTokenInsufficient(@Param("rangeMinute") long rangeMinute);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.InflowTokenInsufficientEvent;
|
||||
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class InflowTokenService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(InflowTokenService.class);
|
||||
|
||||
@Autowired
|
||||
private InflowTokenRepository inflowTokenRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public void checkRecentFails(long rangeMinute) {
|
||||
List<InflowTokenInsufficient> rows = inflowTokenRepository.countTokenInsufficient(rangeMinute);
|
||||
|
||||
for (InflowTokenInsufficient info : rows) {
|
||||
log.debug("유량제어 토큰 획득 실패: {}-{} 최근 {}분 동안 {}건", info.getEaisvcname(), info.getEaisvcdesc(), rangeMinute, info.getCnt());
|
||||
|
||||
//내부직원 알림 발송
|
||||
eventPublisher.publishEvent(InflowTokenInsufficientEvent.from(info, rangeMinute));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.eactive.eai.rms.ext.djb.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig {
|
||||
|
||||
@Bean("asyncExecutor")
|
||||
public Executor asyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(2);
|
||||
executor.setMaxPoolSize(5);
|
||||
executor.setQueueCapacity(20);
|
||||
executor.setThreadNamePrefix("async-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.eactive.eai.rms.ext.djb.async;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.ApiStatusChangedEvent;
|
||||
import com.eactive.eai.rms.ext.djb.event.InflowTokenInsufficientEvent;
|
||||
import com.eactive.eai.rms.ext.djb.swing.service.SwingSendManager;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookSendManager;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AsyncEventListener {
|
||||
|
||||
private final WebhookSendManager webhookSendManager;
|
||||
|
||||
private final SwingSendManager swingSendManager;
|
||||
|
||||
@Async("asyncExecutor")
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onApiStatusChanged(ApiStatusChangedEvent event) {
|
||||
log.debug("API 상태 변경 이벤트 수신: {} {}", event.getEaisvcname(), event.getEvent());
|
||||
webhookSendManager.send(event.getEaisvcname(), event.getEvent());
|
||||
swingSendManager.send(null, 0, 0);
|
||||
}
|
||||
|
||||
@Async("asyncExecutor")
|
||||
@EventListener // 트랜잭션 write 없이 read만 하므로 TransactionalEventListener 불필요
|
||||
public void onInflowTokenFail(InflowTokenInsufficientEvent event) {
|
||||
log.debug("유량제어 토큰획득 실패 이벤트 수신: {} {}건", event.getEaisvcname(), event.getCnt());
|
||||
swingSendManager.send(event.getEaisvcname(), event.getCnt(), event.getRangeMinute());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.eactive.eai.rms.ext.djb.event;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.apistatus.ApiStatusEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class ApiStatusChangedEvent {
|
||||
private final String eaisvcname;
|
||||
private final String eaisvcdesc;
|
||||
private final String event;
|
||||
|
||||
public static ApiStatusChangedEvent from(ApiStatusEvent source) {
|
||||
return new ApiStatusChangedEvent(source.getEaisvcname(), source.getEaisvcdesc(), source.getEvent());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.eactive.eai.rms.ext.djb.event;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.inflow.InflowTokenInsufficient;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class InflowTokenInsufficientEvent {
|
||||
private final String eaisvcname;
|
||||
private final String eaisvcdesc;
|
||||
private final long cnt;
|
||||
private final long rangeMinute;
|
||||
|
||||
public static InflowTokenInsufficientEvent from(InflowTokenInsufficient summary, long rangeMinute) {
|
||||
return new InflowTokenInsufficientEvent(summary.getEaisvcname(), summary.getEaisvcdesc(), summary.getCnt(), rangeMinute);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -43,9 +43,9 @@ import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
* </pre>
|
||||
*/
|
||||
@DisallowConcurrentExecution
|
||||
public class ApiStatusUpdateJob implements Job {
|
||||
public class ApiStatusMonitorJob implements Job {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiStatusUpdateJob.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiStatusMonitorJob.class);
|
||||
|
||||
/** Job 파라미터 키: API 장애기준 시간간격(분) */
|
||||
public static final String KEY_API_STATUS_ERROR_RANGE_MINUTE = "api.status.error.range_minute";
|
||||
+4
-4
@@ -18,7 +18,7 @@ import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.data.ext.djb.inflow.InflowTokenFailService;
|
||||
import com.eactive.eai.rms.data.ext.djb.inflow.InflowTokenService;
|
||||
import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
|
||||
/**
|
||||
@@ -40,9 +40,9 @@ import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
*/
|
||||
|
||||
@DisallowConcurrentExecution
|
||||
public class InflowTokenFailMonitorJob implements Job {
|
||||
public class InflowTokenMonitorJob implements Job {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(InflowTokenFailMonitorJob.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(InflowTokenMonitorJob.class);
|
||||
|
||||
private transient MonitoringContext monitoringContext;
|
||||
|
||||
@@ -72,7 +72,7 @@ public class InflowTokenFailMonitorJob implements Job {
|
||||
}
|
||||
|
||||
monitoringContext = (MonitoringContext) appContext.getBean("monitoringContext");
|
||||
InflowTokenFailService service = appContext.getBean(InflowTokenFailService.class);
|
||||
InflowTokenService service = appContext.getBean(InflowTokenService.class);
|
||||
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.eactive.eai.rms.ext.djb.swing.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SwingSendManager {
|
||||
|
||||
public void send(String eaisvcname, long cnt, long rangeMinute) {
|
||||
log.info("[Swing] 발송 준비: {} 최근 {}분 {}건", eaisvcname, rangeMinute, cnt);
|
||||
// TODO: 알림 발송 로직
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WebhookSendManager {
|
||||
|
||||
public void send(String eaisvcname, String eventType) {
|
||||
log.info("[Webhook] 발송 준비: {} {}", eaisvcname, eventType);
|
||||
// TODO: PTL_WEBHOOK_REQ 조인 조회 후 WebhookService.send() 호출
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user