자동 탐지 미게시 포함 설정 추가

- 설정 키 확인 로직 추가 및 미게시 인터페이스 처리 적용
- 게시/미게시 API 필터링 로직 분리 및 오류 처리 강화
This commit is contained in:
Rinjae
2026-08-19 14:31:12 +09:00
parent 2e30239a90
commit 7b8646ab94
@@ -49,6 +49,12 @@ import com.eactive.eai.rms.data.entity.onl.djb.apistatus.ApiNameRow;
* 검수·게시해야 개발자포탈에 노출되며, {@code PUBLISH}면 탐지 즉시 노출된다.
* {@code OFF} 여도 이미 열려있는 장애의 복구 처리(ERROR_END/DELAY_END)는 계속 동작한다.</p>
*
* <p>개발자포탈 미게시 인터페이스 포함 여부는 {@code djb.apistatus.auto-incident-include-unpublished}
* (기본 {@code false}) 로 정한다. 기본값이면 게시 API 만 이슈에 담고,
* 게시 API 가 하나도 없는 탐지는 기록하지 않는다. {@code true}면 미게시 인터페이스도
* 포함해 건수로 집계된다. 복구 처리는 이 설정과 무관하게
* 이미 이슈에 담긴 API 를 대상으로 동작한다.</p>
*
* <p>점검(CONTROL_*) 은 관리자가 공지사항으로 등록한 점검 일정이 원천이다
* ({@code ApiStatusRepository.findApiStatusEvents} 가 INCIDENT 기간을 읽어 CTRL_YN 을 판정).
* 따라서 CONTROL 이벤트를 다시 기록하면 순환이 되므로 기록하지 않는다.</p>
@@ -96,6 +102,12 @@ public class ApiStatusDetectionService {
/** 오탐이 그대로 고객에게 노출되지 않도록 기본은 검수(DRAFT) */
private static final String DEFAULT_AUTO_INCIDENT_MODE = MODE_DRAFT;
/** 자동 탐지 이슈에 개발자포탈 미게시 인터페이스도 포함할지 여부 - true / false */
public static final String KEY_INCLUDE_UNPUBLISHED = "djb.apistatus.auto-incident-include-unpublished";
/** 포탈 게시 API 장애만 고객 공지 대상이 되도록 기본은 제외(false) */
private static final String DEFAULT_INCLUDE_UNPUBLISHED = "false";
@Autowired
private DjbApistatusIncidentRepository incidentRepository;
@@ -208,6 +220,19 @@ public class ApiStatusDetectionService {
}
boolean autoPublish = MODE_PUBLISH.equals(mode);
// 미게시 인터페이스 제외 설정(false)이면 게시 API 만 남기고, 하나도 없으면 기록하지 않는다
if (!resolveIncludeUnpublished()) {
List<String> published = filterPublished(apiIds);
if (published.isEmpty()) {
log.info("게시 API 없음 - 미게시 인터페이스 제외 설정으로 기록하지 않음: {} {}", event, apiIds);
return;
}
if (published.size() < apiIds.size()) {
log.info("미게시 인터페이스 제외: {} → {}", apiIds, published);
}
apiIds = published;
}
LocalDateTime now = LocalDateTime.now();
String interfaceId = makeInterfaceId(event, apiIds, now);
@@ -314,6 +339,27 @@ public class ApiStatusDetectionService {
}
}
/**
* 자동 탐지 이슈에 개발자포탈 미게시 인터페이스도 포함할지 여부.
*
* <p>PTL_PROPERTY({@code Portal} / {@code djb.apistatus.auto-incident-include-unpublished}) 를 읽는다.
* 최초 접근 시 기본값으로 row 가 자동 생성된다. 기본 {@code false} - 게시 API 만 이슈에 담는다.
* 명시적으로 {@code true}/{@code Y} 를 설정한 경우에만 미게시 인터페이스를 포함하며,
* 알 수 없는 값·조회 실패는 기본값 쪽(false)으로 떨어뜨린다.</p>
*/
private boolean resolveIncludeUnpublished() {
try {
String value = portalPropertyService.getOrCreateProperty(
PROPERTY_GROUP, KEY_INCLUDE_UNPUBLISHED, DEFAULT_INCLUDE_UNPUBLISHED,
"API 상태 자동 탐지 이슈에 포탈 미게시 인터페이스 포함 여부(true/false)");
String normalized = StringUtils.trimToEmpty(value);
return "true".equalsIgnoreCase(normalized) || "Y".equalsIgnoreCase(normalized);
} catch (Exception e) {
log.warn("미게시 인터페이스 포함 여부 조회 실패 - 기본값 {} 적용", DEFAULT_INCLUDE_UNPUBLISHED, e);
return false;
}
}
private void mergeIntoOpenIncident(DjbApistatusIncident incident, String event, IncidentKind kind,
List<String> apiIds, LocalDateTime now, boolean autoPublish) {
Long incidentId = incident.getIncidentId();
@@ -540,22 +586,46 @@ public class ApiStatusDetectionService {
}
/**
* 게시 인터페이스 판정. 조회 실패하면 전부 비게시로 보아 ID·명칭 노출을 막는다.
* 게시 인터페이스 ID 집합 조회. 실패 처리는 호출부 정책에 맡긴다.
*
* <p>판정 조건 두 개가 서로 다른 스키마에 있어 조회를 나눈다 - API 그룹 편성은 AGWAPP,
* 스펙 존재는 EMSAPP(PTL_API_SPEC_INFO). 한 쿼리로 조인하면 tenant=APIGW 커넥션이
* EMSAPP 를 못 봐서 ORA-00942 가 난다.</p>
*/
private Set<String> lookupPublishedApiIds(List<String> apiIds) {
List<String> groupedIds = apiStatusRepository.findDisplayedGroupApiIds(apiIds);
return groupedIds.isEmpty()
? Collections.emptySet()
: new HashSet<>(apiSpecInfoRepository.findApiIdsIn(groupedIds));
}
/**
* 게시 API 만 남긴다 (미게시 인터페이스 제외 설정용). 판정에 실패하면 전체를 유지한다 -
* 제외 판단이 안 되는 상황에서 진짜 장애 기록까지 버리는 쪽이 더 위험하고,
* 명칭 노출은 표기 단계({@link #splitPublished})가 따로 막는다.
*/
private List<String> filterPublished(List<String> apiIds) {
try {
Set<String> publishedIds = lookupPublishedApiIds(apiIds);
return apiIds.stream()
.filter(publishedIds::contains)
.collect(Collectors.toList());
} catch (Exception e) {
log.warn("게시 API 판정 실패 - 미게시 인터페이스 제외 없이 전체 포함", e);
return apiIds;
}
}
/**
* 게시 인터페이스 판정. 조회에 실패하면 전부 비게시로 보아 ID·명칭 노출을 막는다.
*/
private ApiSplit splitPublished(List<String> apiIds) {
if (apiIds == null || apiIds.isEmpty()) {
return new ApiSplit(Collections.emptyList(), 0);
}
Set<String> publishedIds;
try {
List<String> groupedIds = apiStatusRepository.findDisplayedGroupApiIds(apiIds);
publishedIds = groupedIds.isEmpty()
? Collections.emptySet()
: new HashSet<>(apiSpecInfoRepository.findApiIdsIn(groupedIds));
publishedIds = lookupPublishedApiIds(apiIds);
} catch (Exception e) {
// 실패 시 노출하는 쪽으로 기울면 내부 인터페이스가 고객 화면에 새어 나간다
log.warn("게시 API 판정 실패 - 전부 GW 인터페이스로 묶어 표기", e);