Merge remote-tracking branch 'origin/master'
eapim-admin CI / build (push) Waiting to run

This commit is contained in:
Rinjae
2026-07-22 14:39:05 +09:00
@@ -1,8 +1,9 @@
package com.eactive.eai.rms.ext.djb.job; package com.eactive.eai.rms.ext.djb.job;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
@@ -28,7 +29,8 @@ import com.eactive.eai.rms.data.entity.onl.kjb.statistics.QApiStatsHour;
/** /**
* API 로그 테이블을 시간별 통계로 집계하는 배치 작업 * API 로그 테이블을 시간별 통계로 집계하는 배치 작업
* TSEAILGXX → API_STATS_HOUR * TSEAILGXX → API_STATS_HOUR
* 실행 주기: 매시 00:10 (당일 데이터 집계) * 실행 주기: 매시 00:10, 직전 1시간(예: 14:10 실행 시 13:00~13:59:59) 데이터 집계
* (0시대 실행 시 전날 23:00~23:59:59 집계)
*/ */
@Component @Component
public class ApiStatsHourlyAggregationJob implements Job { public class ApiStatsHourlyAggregationJob implements Job {
@@ -59,11 +61,9 @@ public class ApiStatsHourlyAggregationJob implements Job {
DataSourceType dataType = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW); DataSourceType dataType = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW);
DataSourceContextHolder.setDataSourceType(dataType); DataSourceContextHolder.setDataSourceType(dataType);
try { try {
LocalDate targetDate = LocalDate.now(); // 직전 1시간(예: 14:10 실행 -> 13:00~13:59:59). 0시대 실행 시 자동으로 전날 23시로 롤오버됨
if (LocalTime.now().isBefore(LocalTime.of(1, 0))) { LocalDateTime targetHour = LocalDateTime.now().minusHours(1).truncatedTo(ChronoUnit.HOURS);
targetDate = targetDate.minusDays(1); selfJob.executeManual(targetHour);
}
selfJob.executeManual(targetDate);
} catch (Exception e) { } catch (Exception e) {
throw new JobExecutionException(e); throw new JobExecutionException(e);
} finally { } finally {
@@ -72,22 +72,38 @@ public class ApiStatsHourlyAggregationJob implements Job {
} }
/** /**
* 수동 실행 메서드 (날짜 지정) * 수동 실행 메서드 (날짜 지정, 하루 전체 재집계 - 관리자 화면 백필용)
*/ */
@Transactional @Transactional
public int executeManual(LocalDate targetDate) { public int executeManual(LocalDate targetDate) {
LocalDateTime rangeStart = targetDate.atStartOfDay();
return aggregate(rangeStart, rangeStart.plusDays(1));
}
/**
* 수동/스케줄 실행 메서드 (시각 지정, 해당 시각이 속한 1시간만 집계)
*/
@Transactional
public int executeManual(LocalDateTime targetHour) {
LocalDateTime rangeStart = targetHour.truncatedTo(ChronoUnit.HOURS);
return aggregate(rangeStart, rangeStart.plusHours(1));
}
private int aggregate(LocalDateTime rangeStart, LocalDateTime rangeEnd) {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
log.info("=== 시간별 통계 집계 작업 시작 === 대상: {}", targetDate); log.info("=== 시간별 통계 집계 작업 시작 === 대상: {} ~ {}", rangeStart, rangeEnd);
String searchDate = targetDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")); DateTimeFormatter tsFormat = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String logTableName = CommonUtil.getLogTable(searchDate, true); String logTableName = CommonUtil.getLogTable(rangeStart.format(DateTimeFormatter.ofPattern("yyyyMMdd")), true);
String rangeStartStr = rangeStart.format(tsFormat) + "000";
String rangeEndStr = rangeEnd.format(tsFormat) + "000";
// 1. 기존 데이터 삭제 // 1. 대상 구간(rangeStart ~ rangeEnd)의 기존 데이터 삭제 (다른 시간대 데이터는 보존)
QApiStatsHour q = QApiStatsHour.apiStatsHour; QApiStatsHour q = QApiStatsHour.apiStatsHour;
long deletedCount = apiStatsHourService.getJPAQueryFactory() long deletedCount = apiStatsHourService.getJPAQueryFactory()
.delete(q) .delete(q)
.where(q.statTime.goe(targetDate.atStartOfDay()) .where(q.statTime.goe(rangeStart)
.and(q.statTime.lt(targetDate.plusDays(1).atStartOfDay()))) .and(q.statTime.lt(rangeEnd)))
.execute(); .execute();
log.info("기존 데이터 삭제: {} 건", deletedCount); log.info("기존 데이터 삭제: {} 건", deletedCount);
@@ -130,14 +146,15 @@ public class ApiStatsHourlyAggregationJob implements Job {
" , MAX(CASE WHEN LOGPRCSSSERNO = '400' THEN LOGPRCSSSERNO ELSE '' END) AS E400" + " , MAX(CASE WHEN LOGPRCSSSERNO = '400' THEN LOGPRCSSSERNO ELSE '' END) AS E400" +
" , MAX(EAIERRCD) AS ERROR_CODE" + " , MAX(EAIERRCD) AS ERROR_CODE" +
" FROM " + logTableName + " FROM " + logTableName +
" WHERE MSGDPSTYMS LIKE :searchDate || '%'" + " WHERE MSGDPSTYMS >= :rangeStart AND MSGDPSTYMS < :rangeEnd" +
" GROUP BY EAISVCSERNO" + " GROUP BY EAISVCSERNO" +
" ) A LEFT OUTER JOIN TSEAICM20 B ON A.ERROR_CODE = B.CODE AND B.CODEGROUP = 'ERRCODE_TIMEOUT' AND B.USEYN = 'Y' " + " ) A LEFT OUTER JOIN TSEAICM20 B ON A.ERROR_CODE = B.CODE AND B.CODEGROUP = 'ERRCODE_TIMEOUT' AND B.USEYN = 'Y' " +
" GROUP BY SUBSTR(DT,1,10), API_NAME, GW_INSTANCE_ID, BIZ_DIV_CODE, NVL(A.CLIENT_ID, 'NONE')" + " GROUP BY SUBSTR(DT,1,10), API_NAME, GW_INSTANCE_ID, BIZ_DIV_CODE, NVL(A.CLIENT_ID, 'NONE')" +
" , INBOUND_ADAPTER, OUTBOUND_ADAPTER"; " , INBOUND_ADAPTER, OUTBOUND_ADAPTER";
int savedCount = entityManager.createNativeQuery(sql) int savedCount = entityManager.createNativeQuery(sql)
.setParameter("searchDate", searchDate) .setParameter("rangeStart", rangeStartStr)
.setParameter("rangeEnd", rangeEndStr)
.executeUpdate(); .executeUpdate();
long elapsedTime = System.currentTimeMillis() - startTime; long elapsedTime = System.currentTimeMillis() - startTime;