From 0a4b92ed7aa16ba4d7d16270428d37e54acaeb00 Mon Sep 17 00:00:00 2001 From: eastargh Date: Thu, 17 Sep 2026 17:45:18 +0900 Subject: [PATCH] =?UTF-8?q?API=EC=83=81=ED=83=9C=EB=B3=80=ED=99=94?= =?UTF-8?q?=EA=B0=90=EC=8B=9CJOB=20api.status.if=5Fid=5F=EB=A1=9C=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=ED=95=98=EB=8A=94=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=EA=B0=80=20=EC=9E=88=EB=8A=94=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EA=B0=90=EC=8B=9C=EC=A1=B0=EA=B1=B4=EC=97=90=20if?= =?UTF-8?q?=5Fid=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../djb/apistatus/ApiStatusRepository.java | 24 +++++++++- .../ext/djb/apistatus/ApiStatusService.java | 20 +++++++- .../rms/ext/djb/job/ApiStatusMonitorJob.java | 48 ++++++++++++++++++- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusRepository.java b/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusRepository.java index 58e6452..778ab74 100644 --- a/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusRepository.java +++ b/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusRepository.java @@ -73,6 +73,9 @@ public interface ApiStatusRepository extends BaseRepository { + " BETWEEN TO_CHAR(:delayRangeStart,'YYYYMMDDHH24MI')" + " AND TO_CHAR(:rangeEnd,'YYYYMMDDHH24MI'))) AS DELAY_YN" + " FROM TSEAIHE01 A LEFT OUTER JOIN API_STATUS B ON A.EAISVCNAME = B.EAISVCNAME" + // apiIdsProvided='N'이면 전체 API 대상(무조건 참), 'Y'면 apiIds로 좁힌다. + // (apiIds는 :apiIdsProvided='N'일 때도 항상 바인딩되어야 하므로 이 경우 호출측에서 더미 1건을 채워 보낸다) + + " WHERE (:apiIdsProvided = 'N' OR A.EAISVCNAME IN (:apiIds))" + " )" + " ) A WHERE EVENT != 'STAY'") List findApiStatusEvents( @@ -80,7 +83,9 @@ public interface ApiStatusRepository extends BaseRepository { @Param("delayAvgRespTime") int delayAvgRespTime, @Param("errorRangeStart") LocalDateTime errorRangeStart, @Param("delayRangeStart") LocalDateTime delayRangeStart, - @Param("rangeEnd") LocalDateTime rangeEnd + @Param("rangeEnd") LocalDateTime rangeEnd, + @Param("apiIdsProvided") String apiIdsProvided, + @Param("apiIds") Collection apiIds ); /** @@ -113,6 +118,23 @@ public interface ApiStatusRepository extends BaseRepository { @Param("modifiedBy") String modifiedBy, @Param("modifiedDate") LocalDateTime modifiedDate); + /** + * API 상태 변경 히스토리 적재. {@code claimStatusChange}로 선점에 성공한 실행에서만 + * (즉 실제로 상태가 바뀐 건에 대해서만) 1행 기록한다. + */ + @Modifying + @Query(nativeQuery = true, value = + "INSERT INTO API_STATUS_HIST" + + " (HIST_SEQ, EAISVCNAME, STATUS_CODE, PREV_STATUS_CODE, JOBNAME, INSTANCENAME, CREATED_BY, CREATED_DATE)" + + " VALUES (API_STATUS_HIST_SEQ.NEXTVAL, :eaisvcname, :statusCode, :prevStatusCode, :jobName, :instanceName, :createdBy, :createdDate)") + void insertHistory(@Param("eaisvcname") String eaisvcname, + @Param("statusCode") String statusCode, + @Param("prevStatusCode") String prevStatusCode, + @Param("jobName") String jobName, + @Param("instanceName") String instanceName, + @Param("createdBy") String createdBy, + @Param("createdDate") LocalDateTime createdDate); + /** * 판정 구간에 트래픽이 있는 API 의 오류율·지연 판정값. 개발 모드(-Deai.systemmode=D) 진단 로그 전용. * diff --git a/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusService.java b/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusService.java index ad8f8d3..c3a40be 100644 --- a/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusService.java +++ b/src/main/java/com/eactive/eai/rms/ext/djb/apistatus/ApiStatusService.java @@ -7,6 +7,7 @@ import java.net.UnknownHostException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -69,7 +70,7 @@ public class ApiStatusService { } - public void updateApiStatus(HashMap param) { + public void updateApiStatus(HashMap param, List targetApiIds, String jobName) { int errorRate = Integer.parseInt(param.get("errorRate")); int errorRangeMinute = Integer.parseInt(param.get("errorRangeMinute")); @@ -86,12 +87,18 @@ public class ApiStatusService { LocalDateTime errorRangeStart = rangeEnd.minusMinutes(errorRangeMinute); LocalDateTime delayRangeStart = rangeEnd.minusMinutes(delayRangeMinute); + // targetApiIds가 비어있으면 전체 API 대상, 값이 있으면 그 API들로만 판정 대상을 좁힌다 + // (JobDataMap의 api.status.if_id_ 로 시작하는 파라미터들의 값 - ApiStatusMonitorJob 참고) + boolean apiIdsProvided = targetApiIds != null && !targetApiIds.isEmpty(); + List list = apiStatusRepository.findApiStatusEvents( errorRate, delayAvgRespTime, errorRangeStart, delayRangeStart, - rangeEnd + rangeEnd, + apiIdsProvided ? "Y" : "N", + apiIdsProvided ? targetApiIds : Collections.singletonList("") ); HashMap> eventMap = new HashMap<>(); @@ -110,6 +117,15 @@ public class ApiStatusService { log.debug("API 상태 변경: {}-{} {} → {}", event.getEaisvcname(), event.getEaisvcdesc(), event.getEvent(), newStatusCode); + // API 상태 변경 히스토리 적재 (선점에 성공한 실행에서만 - 실제 상태 전이 1건당 1행) + apiStatusRepository.insertHistory( + event.getEaisvcname(), + newStatusCode, + event.getPrevStatusCode(), + jobName, + System.getProperty("inst.Name"), + "SCHEDULER", + LocalDateTime.now()); //이벤트별로 api분리 저장 List apis = (List)eventMap.get(event.getEvent()); diff --git a/src/main/java/com/eactive/eai/rms/ext/djb/job/ApiStatusMonitorJob.java b/src/main/java/com/eactive/eai/rms/ext/djb/job/ApiStatusMonitorJob.java index 9ff60fc..d177111 100644 --- a/src/main/java/com/eactive/eai/rms/ext/djb/job/ApiStatusMonitorJob.java +++ b/src/main/java/com/eactive/eai/rms/ext/djb/job/ApiStatusMonitorJob.java @@ -1,7 +1,9 @@ package com.eactive.eai.rms.ext.djb.job; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -39,6 +41,8 @@ import com.eactive.eai.rms.onl.common.util.DateUtil; * api.status.error.rate: API 장애기준 오류건수 비율(%) (단위: 시간, 기본값: 100) * api.status.delay.range_minute: API 지연기준 판단 시간간격 (단위: 분, 기본값: 1) * api.status.delay.avg_resp_time: API 지연기준 평균응답시간 (단위: 밀리세컨드, 기본값: 10000) + * api.status.if_id_*: 판정 대상 API ID(인터페이스ID). 여러 개면 접두사가 같은 키를 + * 여러 개 등록(api.status.if_id_1, api.status.if_id_2, ...). 미등록 시 전체 API 대상. * * * @@ -64,7 +68,15 @@ public class ApiStatusMonitorJob implements Job { /** Job 파라미터 키: API 지연기준 평균응답시간(ms) */ public static final String KEY_API_STATUS_DELAY_AVG_RESP_TIME = "api.status.delay.avg_resp_time"; - + + /** + * Job 파라미터 키 접두사: 판정 대상 API ID(인터페이스ID) 목록. + * JobDataMap은 배열을 담을 수 없어, 이 접두사로 시작하는 키를 여러 개 등록하면 + * (예: api.status.if_id_1, api.status.if_id_2, ...) 그 값들을 모아 배열로 취급한다. + * 값이 하나도 없으면(=전체 등록 안 함) 기존처럼 전체 API가 판정 대상이다. + */ + public static final String KEY_API_STATUS_IF_ID_PREFIX = "api.status.if_id_"; + public static final String DEFAULT_ERROR_RANGE_MINUTE = "1"; public static final String DEFAULT_ERROR_RATE = "100"; public static final String DEFAULT_DELAY_RANGE_MINUTE = "1"; @@ -96,6 +108,11 @@ public class ApiStatusMonitorJob implements Job { HashMap param = this.checkParameters(jobDataMap); + //다른 조건으로 특정 API들을 감시하기 위해 Job을 다른이름으로 등록하여 추가로 감시한다. + //파라미터에 api.status.if_id_(n)=ASCORBED000S1 을 필요한 만큼 추가한다(최대 500개) + List apiIds = this.collectApiIds(jobDataMap); + String jobName = context.getJobDetail().getKey().getName(); + ApplicationContext appContext; try { @@ -111,7 +128,7 @@ public class ApiStatusMonitorJob implements Job { DataSourceContextHolder.setDataSourceType( DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW)); try { - apiStatusUpdateService.updateApiStatus(param); + apiStatusUpdateService.updateApiStatus(param, apiIds, jobName); } catch (Exception e) { log.error("ApiStatusUpdateJob execution failed", e); @@ -184,6 +201,33 @@ public class ApiStatusMonitorJob implements Job { return param; } + /** + * KEY_API_STATUS_IF_ID_PREFIX(api.status.if_id_)로 시작하는 Job 파라미터들의 값을 모아 + * 판정 대상 API ID 목록을 만든다. JobDataMap은 배열을 지원하지 않아 접두사 붙은 키를 + * 여러 개 등록하는 방식으로 배열을 흉내낸다. 값이 없으면(=아무 키도 등록 안 함) 빈 리스트를 + * 반환하며, 이 경우 {@code ApiStatusService.updateApiStatus}는 전체 API를 판정 대상으로 삼는다. + */ + private List collectApiIds(JobDataMap jobDataMap) { + List apiIds = new ArrayList<>(); + + if (jobDataMap == null) { + return apiIds; + } + + for (String key : jobDataMap.getKeys()) { + if (!key.startsWith(KEY_API_STATUS_IF_ID_PREFIX)) { + continue; + } + + String value = jobDataMap.getString(key); + if (StringUtils.isNotBlank(value)) { + apiIds.add(value.trim()); + } + } + + return apiIds; + } + /** * 개발 모드 여부 확인 * @return eai.systemmode=D 이면 true