From 792aea12466738c5a4812f8e86a796370a9fa57e Mon Sep 17 00:00:00 2001 From: Rinjae Date: Tue, 13 Jan 2026 21:54:21 +0900 Subject: [PATCH] =?UTF-8?q?ObpGwMetric=20UK=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onl/apim/obp/ObpGwMetricManService.java | 92 +++++++++++++------ .../common/service/ObpGwMetricHourJob.java | 2 + 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpGwMetricManService.java b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpGwMetricManService.java index 6ad1045..814f13c 100644 --- a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpGwMetricManService.java +++ b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpGwMetricManService.java @@ -12,6 +12,7 @@ import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricService; import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricVO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -185,40 +186,59 @@ public class ObpGwMetricManService extends BaseService { int insertCount = 0; int updateCount = 0; + int conflictRetryCount = 0; for (ObpGwMetricVO vo : aggregatedList) { LocalDateTime timesliceDateTime = vo.getTimesliceAsLocalDateTime(); - Optional existing = obpGwMetricService.findByUniqueKey( - timesliceDateTime, - vo.getApiId(), - vo.getClientId(), - vo.getHostname(), - vo.getOrgId() - ); + try { + Optional existing = obpGwMetricService.findByUniqueKey( + timesliceDateTime, + vo.getApiId(), + vo.getClientId(), + vo.getHostname(), + vo.getOrgId() + ); - if (existing.isPresent()) { - // UPDATE: 기존 데이터 갱신 - ObpGwMetric entity = existing.get(); - entity.setAttemptedCount(vo.getAttemptedCount()); - entity.setCompletedCount(vo.getCompletedCount()); - entity.setApiName(apiNameMap.get(vo.getApiId())); - entity.setUri(uriMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 URI 조회 - entity.setMethod(methodMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 HTTP Method 조회 - entity.setAppId(appIdMap.get(vo.getOrgId())); - entity.setUpdateCount(entity.getUpdateCount() + 1); // 보정 횟수 증가 - entity.setUpdatedAt(LocalDateTime.now()); - entity.setUpdatedBy("GwMetricHourJob"); - obpGwMetricService.save(entity); - updateCount++; - } else { - // INSERT: 신규 데이터 생성 - ObpGwMetric entity = convertToEntity(vo, apiNameMap, uriMap, methodMap, appIdMap); - obpGwMetricService.save(entity); - insertCount++; + if (existing.isPresent()) { + // UPDATE: 기존 데이터 갱신 + updateExistingMetric(existing.get(), vo, apiNameMap, uriMap, methodMap, appIdMap); + updateCount++; + } else { + // INSERT: 신규 데이터 생성 + ObpGwMetric entity = convertToEntity(vo, apiNameMap, uriMap, methodMap, appIdMap); + obpGwMetricService.save(entity); + insertCount++; + } + } catch (DataIntegrityViolationException e) { + // Unique constraint violation 발생 시 UPDATE로 재시도 + log.debug("UK 충돌 발생, UPDATE로 재시도: timeslice={}, apiId={}, clientId={}", + timesliceDateTime, vo.getApiId(), vo.getClientId()); + + Optional existing = obpGwMetricService.findByUniqueKey( + timesliceDateTime, + vo.getApiId(), + vo.getClientId(), + vo.getHostname(), + vo.getOrgId() + ); + + if (existing.isPresent()) { + updateExistingMetric(existing.get(), vo, apiNameMap, uriMap, methodMap, appIdMap); + updateCount++; + conflictRetryCount++; + } else { + // 재조회에서도 없으면 예외 재발생 (비정상 상황) + log.error("UK 충돌 후 재조회 실패: timeslice={}, apiId={}", timesliceDateTime, vo.getApiId()); + throw e; + } } } + if (conflictRetryCount > 0) { + log.info("[4단계] UK 충돌 재시도 건수: {}", conflictRetryCount); + } + log.info("[4단계] UPSERT 완료: INSERT={}, UPDATE={}, elapsed={}ms", insertCount, updateCount, System.currentTimeMillis() - step4Start); @@ -247,6 +267,26 @@ public class ObpGwMetricManService extends BaseService { return existing; } + /** + * 기존 엔티티 업데이트 + */ + private void updateExistingMetric(ObpGwMetric entity, ObpGwMetricVO vo, + Map apiNameMap, + Map uriMap, + Map methodMap, + Map appIdMap) { + entity.setAttemptedCount(vo.getAttemptedCount()); + entity.setCompletedCount(vo.getCompletedCount()); + entity.setApiName(apiNameMap.get(vo.getApiId())); + entity.setUri(uriMap.get(vo.getEaiSvcSerno())); + entity.setMethod(methodMap.get(vo.getEaiSvcSerno())); + entity.setAppId(appIdMap.get(vo.getOrgId())); + entity.setUpdateCount(entity.getUpdateCount() + 1); + entity.setUpdatedAt(LocalDateTime.now()); + entity.setUpdatedBy("GwMetricHourJob"); + obpGwMetricService.save(entity); + } + /** * VO → Entity 변환 */ diff --git a/src/main/java/com/eactive/eai/rms/onl/common/service/ObpGwMetricHourJob.java b/src/main/java/com/eactive/eai/rms/onl/common/service/ObpGwMetricHourJob.java index 7b93297..e06836e 100644 --- a/src/main/java/com/eactive/eai/rms/onl/common/service/ObpGwMetricHourJob.java +++ b/src/main/java/com/eactive/eai/rms/onl/common/service/ObpGwMetricHourJob.java @@ -4,6 +4,7 @@ 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.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; @@ -41,6 +42,7 @@ import org.springframework.context.ApplicationContext; * jobDataMap.put("aggregation.hour.range", "3"); * */ +@DisallowConcurrentExecution public class ObpGwMetricHourJob implements Job { private static final Logger log = LoggerFactory.getLogger(ObpGwMetricHourJob.class);