From d275aa12c4c9f7f4be8a7d5454079da196cec56f Mon Sep 17 00:00:00 2001
From: Rinjae
Date: Tue, 1 Sep 2026 14:50:39 +0900
Subject: [PATCH] =?UTF-8?q?Admin=20GatewayClient=20=EB=8B=A4=EC=A4=91=20ba?=
=?UTF-8?q?se=20URL=20=EB=B0=8F=20failover=20=EB=A1=9C=EC=A7=81=20?=
=?UTF-8?q?=EC=B6=94=EA=B0=80:=20-=20admin.base-url=20=EB=8B=A4=EC=A4=91?=
=?UTF-8?q?=20=EC=A3=BC=EC=86=8C=20=EC=A7=80=EC=9B=90=20=EB=B0=8F=20?=
=?UTF-8?q?=EC=88=9C=EC=B0=A8=20failover=20=EA=B5=AC=ED=98=84=20-=20RestTe?=
=?UTF-8?q?mplate=20=ED=83=80=EC=9E=84=EC=95=84=EC=9B=83=20=EC=84=A4?=
=?UTF-8?q?=EC=A0=95=20=EB=B3=80=EA=B2=BD=20(=EC=97=B0=EA=B2=B0/=EC=9D=BD?=
=?UTF-8?q?=EA=B8=B0:=205=EC=B4=88=EB=A1=9C=20=EB=8B=A8=EC=B6=95)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../apps/app/service/AdminGatewayClient.java | 91 ++++++++++++++++---
.../portal/config/RestTemplateConfig.java | 8 +-
2 files changed, 82 insertions(+), 17 deletions(-)
diff --git a/src/main/java/com/eactive/apim/portal/apps/app/service/AdminGatewayClient.java b/src/main/java/com/eactive/apim/portal/apps/app/service/AdminGatewayClient.java
index 7e140f3..7915a04 100644
--- a/src/main/java/com/eactive/apim/portal/apps/app/service/AdminGatewayClient.java
+++ b/src/main/java/com/eactive/apim/portal/apps/app/service/AdminGatewayClient.java
@@ -1,18 +1,28 @@
package com.eactive.apim.portal.apps.app.service;
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
/**
* 관리자(admin) 포털의 내부 API를 호출하는 클라이언트.
*
* GW 인증서버(TSEAIAU01) 제어는 포털이 직접 하지 않고, broadcast 인프라를 갖춘 admin 에 위임한다.
- * admin base URL 은 {@code PTL_PROPERTY} (group={@code Portal}, name={@code djb.admin.base-url}) 에서 조회한다.
+ * admin base URL 은 {@code PTL_PROPERTY} (group={@code Portal}, name={@code admin.base-url}) 에서 조회한다.
+ *
+ * 다중 base URL / failover — 프로퍼티 값에 콤마({@code ,}) 또는 개행으로 여러 admin 주소를 넣을 수 있다.
+ * 호출은 기재된 순서대로 시도하며, 통신 오류(연결 실패/타임아웃/HTTP 오류)면 다음 주소로 넘어간다.
+ * 모두 실패하면 마지막 오류를 던진다. 반면 admin 이 정상 응답하면서 {@code success=false} 를 준 것은
+ * 업무 처리 실패이므로 failover 하지 않고 즉시 실패시킨다(다른 노드도 같은 결과이며 중복 처리 위험).
*/
@Slf4j
@Service
@@ -22,6 +32,8 @@ public class AdminGatewayClient {
private static final String PROP_GROUP = "Portal";
private static final String PROP_ADMIN_BASE_URL = "admin.base-url";
private static final String DEFAULT_ADMIN_BASE_URL = "http://localhost:39120";
+ private static final String PROP_ADMIN_BASE_URL_DESC =
+ "admin(관리자포털) 내부 API base URL. 콤마(,) 또는 줄바꿈으로 여러 개 지정 시 앞에서부터 failover";
private static final String CLIENT_BLOCK_PATH = "/onl/admin/authserver/clientBlock.json?clientId={clientId}";
private final RestTemplate restTemplate;
@@ -30,26 +42,79 @@ public class AdminGatewayClient {
/**
* clientId 의 GW 인증 클라이언트 차단(appstatus=0) + GW 캐시 리로드를 admin 에 요청한다.
*
+ * base URL 이 여러 개면 앞에서부터 순서대로 시도한다(failover).
+ *
* @param clientId 차단할 클라이언트 ID
- * @throws RuntimeException admin 미응답/네트워크 오류 또는 admin 처리 실패 시 (호출측에서 처리)
+ * @throws RuntimeException admin 미응답/네트워크 오류(전 노드 실패) 또는 admin 처리 실패 시 (호출측에서 처리)
*/
public void blockClient(String clientId) {
- String baseUrl = portalPropertyService.getOrCreateProperty(
- PROP_GROUP, PROP_ADMIN_BASE_URL, DEFAULT_ADMIN_BASE_URL, "admin(관리자포털) 내부 API base URL");
+ List baseUrls = resolveBaseUrls();
- String url = stripTrailingSlashes(baseUrl) + CLIENT_BLOCK_PATH;
+ RestClientException lastError = null;
+ for (int i = 0; i < baseUrls.size(); i++) {
+ String baseUrl = baseUrls.get(i);
+ String url = baseUrl + CLIENT_BLOCK_PATH;
- // 네트워크/HTTP 오류는 RestTemplate 이 예외로 던진다.
- ResponseEntity