OBP GwMetric 검증
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# ObpGwMetricHourJob
|
||||
- Job명 : ObpGwMetricHourJob
|
||||
- 설명 : GW 시간당 거래 지표 - OBP 과금기초데이터
|
||||
- com.eactive.eai.rms.onl.common.service.ObpGwMetricHourJob
|
||||
- aggregation.hour.range : 집계 범위(최대 24로 제한)
|
||||
@@ -668,7 +668,4 @@ insert into EMSADM.TSEAIRM24 (PRPTYGROUPNAME, PRPTYNAME, PRPTY2VAL) values ('Mon
|
||||
insert into EMSADM.TSEAIRM24 (PRPTYGROUPNAME, PRPTYNAME, PRPTY2VAL) values ('Monitoring', 'kjb.obp.query_partnercode_uri', '/api/customer/findCustomerByBusinessManRegistrationNo/%s');
|
||||
insert into EMSADM.TSEAIRM24 (PRPTYGROUPNAME, PRPTYNAME, PRPTY2VAL) values ('Monitoring', 'kjb.obp.create_partnercode_uri', '/not-yet-implement/%s');
|
||||
commit;
|
||||
```
|
||||
## 라이선스
|
||||
|
||||
© 광주은행 (Kwangju Bank)
|
||||
```
|
||||
@@ -3,6 +3,7 @@ package com.eactive.eai.rms.data.entity.onl.apim.obp;
|
||||
import com.eactive.eai.rms.common.base.SqlMapClientTemplateDao;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -44,16 +45,19 @@ public class ObpGwMetricDAO extends SqlMapClientTemplateDao {
|
||||
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("schemaId", schemaId);
|
||||
paramMap.put("apiIds", apiIds);
|
||||
paramMap.put("apiIds", new ArrayList<>(apiIds)); // Set → List 변환 (iBATIS iterate 호환)
|
||||
|
||||
List<Map<String, String>> resultList = this.template.queryForList("ObpGwMetric.selectApiNames", paramMap);
|
||||
|
||||
return resultList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
m -> m.get("API_ID"),
|
||||
m -> m.get("API_NAME"),
|
||||
(v1, v2) -> v1
|
||||
));
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (Map<String, String> m : resultList) {
|
||||
String apiId = m.get("API_ID");
|
||||
String apiName = m.get("API_NAME");
|
||||
if (apiId != null && apiName != null) {
|
||||
result.put(apiId, apiName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,16 +71,19 @@ public class ObpGwMetricDAO extends SqlMapClientTemplateDao {
|
||||
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("schemaId", schemaId);
|
||||
paramMap.put("apiIds", apiIds);
|
||||
paramMap.put("apiIds", new ArrayList<>(apiIds)); // Set → List 변환 (iBATIS iterate 호환)
|
||||
|
||||
List<Map<String, String>> resultList = this.template.queryForList("ObpGwMetric.selectUris", paramMap);
|
||||
|
||||
return resultList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
m -> m.get("API_ID"),
|
||||
m -> m.get("URI"),
|
||||
(v1, v2) -> v1
|
||||
));
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (Map<String, String> m : resultList) {
|
||||
String apiId = m.get("API_ID");
|
||||
String uri = m.get("URI");
|
||||
if (apiId != null && uri != null) {
|
||||
result.put(apiId, uri);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,15 +96,18 @@ public class ObpGwMetricDAO extends SqlMapClientTemplateDao {
|
||||
}
|
||||
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("orgIds", orgIds);
|
||||
paramMap.put("orgIds", new ArrayList<>(orgIds)); // Set → List 변환 (iBATIS iterate 호환)
|
||||
|
||||
List<Map<String, String>> resultList = this.template.queryForList("ObpGwMetric.selectAppIdsByOrgIds", paramMap);
|
||||
|
||||
return resultList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
m -> m.get("ORG_ID"),
|
||||
m -> m.get("APP_ID"),
|
||||
(v1, v2) -> v1
|
||||
));
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (Map<String, String> m : resultList) {
|
||||
String orgId = m.get("ORG_ID");
|
||||
String appId = m.get("APP_ID");
|
||||
if (orgId != null && appId != null) {
|
||||
result.put(orgId, appId);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.obp;
|
||||
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
import com.eactive.eai.rms.data.jpa.AbstractEMSDataSerivce;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -14,13 +13,19 @@ import java.util.Optional;
|
||||
*/
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class ObpGwMetricService extends AbstractEMSDataSerivce<ObpGwMetric, String, ObpGwMetricRepository> {
|
||||
public class ObpGwMetricService {
|
||||
|
||||
private final ObpGwMetricRepository repository;
|
||||
|
||||
public ObpGwMetricService(ObpGwMetricRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPSERT 판단을 위한 기존 데이터 조회
|
||||
*/
|
||||
public Optional<ObpGwMetric> findByUniqueKey(LocalDateTime timeslice, String apiId, String clientId, String hostname, String orgId) {
|
||||
return getRepository().findByTimesliceAndApiIdAndClientIdAndHostnameAndOrgId(
|
||||
return repository.findByTimesliceAndApiIdAndClientIdAndHostnameAndOrgId(
|
||||
timeslice, apiId, clientId, hostname, orgId);
|
||||
}
|
||||
|
||||
@@ -28,27 +33,27 @@ public class ObpGwMetricService extends AbstractEMSDataSerivce<ObpGwMetric, Stri
|
||||
* 특정 시간대의 모든 GwMetric 데이터 조회
|
||||
*/
|
||||
public List<ObpGwMetric> findByTimeslice(LocalDateTime timeslice) {
|
||||
return getRepository().findByTimeslice(timeslice);
|
||||
return repository.findByTimeslice(timeslice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 시간 범위의 GwMetric 데이터 조회
|
||||
*/
|
||||
public List<ObpGwMetric> findByTimesliceBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return getRepository().findByTimesliceBetween(startTime, endTime);
|
||||
return repository.findByTimesliceBetween(startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 저장 (INSERT 또는 UPDATE)
|
||||
*/
|
||||
public ObpGwMetric save(ObpGwMetric entity) {
|
||||
return getRepository().save(entity);
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 목록 저장
|
||||
*/
|
||||
public List<ObpGwMetric> saveAll(List<ObpGwMetric> entities) {
|
||||
return getRepository().saveAll(entities);
|
||||
return repository.saveAll(entities);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ObpGwMetricVO {
|
||||
if (timeslice == null || timeslice.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// yyyyMMddHH0000000 형식에서 앞 10자리(yyyyMMddHH)만 사용
|
||||
// "yyyyMMddHH0000000" 형식에서 앞 10자리(yyyyMMddHH)만 사용
|
||||
String dateTimeStr = timeslice.substring(0, 10) + "0000";
|
||||
return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
}
|
||||
|
||||
@@ -31,11 +31,13 @@ public class ObpGwMetricManService extends BaseService {
|
||||
private static final Logger log = LoggerFactory.getLogger(ObpGwMetricManService.class);
|
||||
|
||||
/**
|
||||
* 집계 범위 시간 (단위: 시간)
|
||||
* 기본 집계 범위 시간 (단위: 시간)
|
||||
* - 1: 직전 1시간만 집계
|
||||
* - 5: 직전 5시간까지 각각 1시간 단위로 집계
|
||||
*
|
||||
* <p>Job 파라미터로 오버라이드 가능 (aggregation.hour.range)</p>
|
||||
*/
|
||||
private static final int AGGREGATION_HOUR_RANGE = 1;
|
||||
public static final int DEFAULT_AGGREGATION_HOUR_RANGE = 1;
|
||||
|
||||
private static final DateTimeFormatter TIMESLICE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHH0000000");
|
||||
private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
||||
@@ -50,22 +52,35 @@ public class ObpGwMetricManService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 다중 시간대 집계 실행 (Job에서 호출)
|
||||
* 다중 시간대 집계 실행 (Job에서 호출) - 기본 집계 범위 사용
|
||||
*/
|
||||
public void executeHourlyAggregation() {
|
||||
executeHourlyAggregation(DEFAULT_AGGREGATION_HOUR_RANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 다중 시간대 집계 실행 (Job에서 호출)
|
||||
*
|
||||
* @param aggregationHourRange 집계 범위 시간 (단위: 시간)
|
||||
* 예: 1=직전 1시간, 3=직전 3시간 각각 집계
|
||||
*/
|
||||
public void executeHourlyAggregation(int aggregationHourRange) {
|
||||
long totalStartTime = System.currentTimeMillis();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime baseHour = now.truncatedTo(ChronoUnit.HOURS); // 현재 시간의 정각
|
||||
|
||||
log.info("========== ObpGwMetric 집계 시작 ==========");
|
||||
log.info("실행 시간: {}, AGGREGATION_HOUR_RANGE: {}", now, AGGREGATION_HOUR_RANGE);
|
||||
log.info("실행 시간: {}, aggregationHourRange: {}", now, aggregationHourRange);
|
||||
|
||||
for (int i = 1; i <= AGGREGATION_HOUR_RANGE; i++) {
|
||||
for (int i = 1; i <= aggregationHourRange; i++) {
|
||||
LocalDateTime targetHour = baseHour.minusHours(i);
|
||||
log.info("집계 대상 시간대: {}", targetHour);
|
||||
createHourlyData(targetHour);
|
||||
}
|
||||
|
||||
long totalElapsed = System.currentTimeMillis() - totalStartTime;
|
||||
log.info("========== ObpGwMetric 집계 완료 ==========");
|
||||
log.info("전체 집계 소요시간: {}ms ({}초)", totalElapsed, String.format("%.2f", totalElapsed / 1000.0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +199,8 @@ public class ObpGwMetricManService extends BaseService {
|
||||
entity.setUri(uriMap.get(vo.getApiId()));
|
||||
entity.setAppId(appIdMap.get(vo.getOrgId()));
|
||||
entity.setUpdateCount(entity.getUpdateCount() + 1); // 보정 횟수 증가
|
||||
entity.setUpdatedAt(LocalDateTime.now());
|
||||
entity.setUpdatedBy("GwMetricHourJob");
|
||||
obpGwMetricService.save(entity);
|
||||
updateCount++;
|
||||
} else {
|
||||
@@ -239,6 +256,8 @@ public class ObpGwMetricManService extends BaseService {
|
||||
entity.setUri(uriMap.get(vo.getApiId()));
|
||||
entity.setAppId(appIdMap.get(vo.getOrgId()));
|
||||
entity.setUpdateCount(0);
|
||||
entity.setCreatedAt(LocalDateTime.now());
|
||||
entity.setCreatedBy("GwMetricHourJob");
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.onl.apim.obp.ObpGwMetricManService;
|
||||
import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -22,18 +23,45 @@ import org.springframework.context.ApplicationContext;
|
||||
* <li>보정 (15분): 0 5,20,35,50 * * * ? (15분 간격 4회 실행)</li>
|
||||
* <li>보정 (10분): 0 5,15,25,35,45,55 * * * ? (10분 간격 6회 실행)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Job 파라미터 (JobDataMap):</p>
|
||||
* <ul>
|
||||
* <li><b>aggregation.hour.range</b>: 집계 범위 시간 (단위: 시간, 기본값: 1)
|
||||
* <ul>
|
||||
* <li>1: 직전 1시간만 집계</li>
|
||||
* <li>3: 직전 3시간 각각 집계</li>
|
||||
* <li>5: 직전 5시간 각각 집계</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>예시 (Quartz 스케줄 등록 시):</p>
|
||||
* <pre>
|
||||
* JobDataMap jobDataMap = new JobDataMap();
|
||||
* jobDataMap.put("aggregation.hour.range", "3");
|
||||
* </pre>
|
||||
*/
|
||||
public class ObpGwMetricHourJob implements Job {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ObpGwMetricHourJob.class);
|
||||
|
||||
/** Job 파라미터 키: 집계 범위 시간 */
|
||||
public static final String PARAM_AGGREGATION_HOUR_RANGE = "aggregation.hour.range";
|
||||
|
||||
/** 기본 집계 범위 시간 (시간 단위) */
|
||||
public static final int DEFAULT_AGGREGATION_HOUR_RANGE = 1;
|
||||
|
||||
private transient MonitoringContext monitoringContext;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
log.info("*** START ObpGwMetricHourJob run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
|
||||
|
||||
ApplicationContext appContext = null;
|
||||
// Job 파라미터 로깅
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
logJobParameters(jobDataMap);
|
||||
|
||||
ApplicationContext appContext;
|
||||
try {
|
||||
appContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext");
|
||||
} catch (SchedulerException e) {
|
||||
@@ -44,8 +72,11 @@ public class ObpGwMetricHourJob implements Job {
|
||||
monitoringContext = (MonitoringContext) appContext.getBean("monitoringContext");
|
||||
ObpGwMetricManService obpGwMetricManService = appContext.getBean(ObpGwMetricManService.class);
|
||||
|
||||
// 집계 범위 시간 파라미터 파싱
|
||||
int aggregationHourRange = parseAggregationHourRange(jobDataMap);
|
||||
|
||||
try {
|
||||
obpGwMetricManService.executeHourlyAggregation();
|
||||
obpGwMetricManService.executeHourlyAggregation(aggregationHourRange);
|
||||
} catch (Exception e) {
|
||||
log.error("ObpGwMetricHourJob execution failed", e);
|
||||
throw new JobExecutionException(e);
|
||||
@@ -53,4 +84,64 @@ public class ObpGwMetricHourJob implements Job {
|
||||
|
||||
log.info("*** END ObpGwMetricHourJob run({})", DateUtil.getDateTime("yyyy-MM-dd HH:mm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Job 파라미터 로깅
|
||||
*/
|
||||
private void logJobParameters(JobDataMap jobDataMap) {
|
||||
if (jobDataMap == null || jobDataMap.isEmpty()) {
|
||||
log.debug("Job 파라미터 없음 (기본값 사용)");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder("Job 파라미터: ");
|
||||
for (String key : jobDataMap.getKeys()) {
|
||||
sb.append(key).append("=").append(jobDataMap.getString(key)).append(", ");
|
||||
}
|
||||
log.info(sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 집계 범위 시간 파라미터 파싱
|
||||
*
|
||||
* @param jobDataMap Job 파라미터 맵
|
||||
* @return 집계 범위 시간 (파싱 실패 시 기본값 반환)
|
||||
*/
|
||||
private int parseAggregationHourRange(JobDataMap jobDataMap) {
|
||||
if (jobDataMap == null) {
|
||||
return DEFAULT_AGGREGATION_HOUR_RANGE;
|
||||
}
|
||||
|
||||
try {
|
||||
String value = jobDataMap.getString(PARAM_AGGREGATION_HOUR_RANGE);
|
||||
if (value != null && !value.trim().isEmpty()) {
|
||||
int parsedValue = Integer.parseInt(value.trim());
|
||||
if (parsedValue < 1) {
|
||||
log.warn("aggregation.hour.range 값이 1 미만입니다. 기본값({}) 사용: input={}",
|
||||
DEFAULT_AGGREGATION_HOUR_RANGE, parsedValue);
|
||||
return DEFAULT_AGGREGATION_HOUR_RANGE;
|
||||
}
|
||||
// 개발 모드(D)가 아닌 경우에만 24시간 제한 적용
|
||||
if (parsedValue > 24 && !isDevMode()) {
|
||||
log.warn("aggregation.hour.range 값이 24 초과입니다. 24로 제한: input={}", parsedValue);
|
||||
return 24;
|
||||
}
|
||||
return parsedValue;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("aggregation.hour.range 파싱 실패, 기본값({}) 사용: {}",
|
||||
DEFAULT_AGGREGATION_HOUR_RANGE, e.getMessage());
|
||||
}
|
||||
|
||||
return DEFAULT_AGGREGATION_HOUR_RANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 개발 모드 여부 확인
|
||||
* @return eai.systemmode=D 이면 true
|
||||
*/
|
||||
private boolean isDevMode() {
|
||||
String systemMode = System.getProperty("eai.systemmode", "");
|
||||
return "D".equalsIgnoreCase(systemMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
<!--
|
||||
EAIBZWKDSTCD별 시간대 로그 집계 (Index Range Scan 활용)
|
||||
|
||||
에러 판단 기준 (DailyBackup-oracle.xml 참고):
|
||||
- 에러 조건: RSPNSERRCDNAME LIKE 'RE%' OR RSPNSERRCDNAME LIKE 'RF%'
|
||||
- 성공 조건: 위 조건의 반대 (NULL 또는 RE%/RF%가 아닌 경우)
|
||||
에러 판단 기준:
|
||||
- 성공 조건: RSPNSERRCDNAME IS NULL 또는 RSPNSERRCDNAME LIKE 'ESB%'
|
||||
- 에러 조건: RE%, RF%, REC%, RIB%, 기타 모든 에러 코드
|
||||
|
||||
성능 최적화:
|
||||
- PK 인덱스 (EAIBZWKDSTCD, MSGDPSTYMS, EAISVCSERNO, LOGPRCSSSERNO) 활용
|
||||
@@ -41,8 +41,7 @@
|
||||
'$timeslice$' AS TIMESLICE,
|
||||
SUM(CASE WHEN LOGPRCSSSERNO = '100' THEN 1 ELSE 0 END) AS ATTEMPTED_COUNT,
|
||||
SUM(CASE WHEN LOGPRCSSSERNO = '400'
|
||||
AND (RSPNSERRCDNAME IS NULL
|
||||
OR (RSPNSERRCDNAME NOT LIKE 'RE%' AND RSPNSERRCDNAME NOT LIKE 'RF%'))
|
||||
AND (RSPNSERRCDNAME IS NULL OR RSPNSERRCDNAME LIKE 'ESB%')
|
||||
THEN 1 ELSE 0 END) AS COMPLETED_COUNT
|
||||
FROM $schemaId$.$tableName$
|
||||
WHERE EAIBZWKDSTCD = #bzwkCode#
|
||||
@@ -64,11 +63,11 @@
|
||||
</iterate>
|
||||
</statement>
|
||||
|
||||
<!-- URI 조회 (TSEAIHS04) -->
|
||||
<!-- URI 조회 (TSEAIHS04) - APIFULLPATH 사용 -->
|
||||
<statement id="selectUris" parameterClass="java.util.HashMap" resultClass="java.util.HashMap">
|
||||
SELECT
|
||||
EAISVCNAME AS API_ID,
|
||||
BZWKSVCKEYNAME AS URI
|
||||
APIFULLPATH AS URI
|
||||
FROM $schemaId$.TSEAIHS04
|
||||
WHERE EAISVCNAME IN
|
||||
<iterate property="apiIds" open="(" close=")" conjunction=",">
|
||||
|
||||
Reference in New Issue
Block a user