httpClient 수정
This commit is contained in:
@@ -132,7 +132,7 @@ public class AlarmStateManager {
|
||||
payload = UmsRequestPayload.builder()
|
||||
.content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build())
|
||||
.cellphone(cellPhone).build();
|
||||
|
||||
logger.info("Alarm is disabled, UmsRequestPayload = {}", payload);
|
||||
usmService.send(payload);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.eactive.eai.custom.alarm.ums;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -49,7 +50,17 @@ public class UmsSendManager {
|
||||
void sendMessage() throws Exception {
|
||||
UmsRequestPayload payload;
|
||||
while ((payload = queue.poll()) != null) {
|
||||
umsService.send(payload);
|
||||
final UmsRequestPayload finalPayload = payload;
|
||||
CompletableFuture.runAsync(() -> {
|
||||
UmsCallResult result = null;
|
||||
try {
|
||||
result = umsService.send(finalPayload);
|
||||
} catch (Exception e) {
|
||||
logger.error("UMS 전송 실패", e);
|
||||
}finally {
|
||||
logger.info(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,135 +1,154 @@
|
||||
package com.eactive.eai.custom.alarm.ums;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.hc.core5.http.ProtocolException;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.util.TimeValue;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.util.Jsons;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
|
||||
import com.eactive.eai.custom.alarm.ums.payload.ValidationUtil;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
@Component
|
||||
public class UmsService {
|
||||
|
||||
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||
|
||||
private final static String UMS_GROUP_PROP_NAME = "UMS";
|
||||
private final static String UMS_PROP_HOST = "host";
|
||||
private final static String UMS_PROP_URL = "url";
|
||||
private final static String UMS_PROP_API_KEY = "apiKey";
|
||||
private final static String UMS_URL = "http://172.31.35.144:9021";
|
||||
private final static String API_KEY = "7cca6d58-e4f7-474d-9edd-525806bc99ff";
|
||||
private final static String SEND_URL = "/ums/openapi/send";
|
||||
private final static String CONTENT_TYPE = "application/json; charset=utf-8";
|
||||
private final static String AUTHORIZATION_FMT = "Bearer %s";
|
||||
// 설정 상수
|
||||
private final static String UMS_GROUP_PROP_NAME = "UMS";
|
||||
private final static String UMS_PROP_HOST = "host";
|
||||
private final static String UMS_PROP_URL = "url";
|
||||
private final static String UMS_PROP_API_KEY = "apiKey";
|
||||
private final static String UMS_PROP_CONNECTION_TIMEOUT = "timeout.connection.ms";
|
||||
private final static String UMS_PROP_TIMEOUT = "timeout.ms";
|
||||
|
||||
// 기본값
|
||||
private final static String DEFAULT_UMS_URL = "http://172.31.35.144:9021";
|
||||
private final static String DEFAULT_SEND_URI = "/ums/openapi/send";
|
||||
private final static String DEFAULT_API_KEY = "7cca6d58-e4f7-474d-9edd-525806bc99ff";
|
||||
private final static String AUTHORIZATION_FMT = "Bearer %s";
|
||||
|
||||
public Future<UmsCallResult> send(UmsRequestPayload payload) throws Exception {
|
||||
// 재사용되는 HttpClient (Thread-Safe)
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
if (payload.getContent() == null) {
|
||||
throw new IllegalArgumentException("content is null");
|
||||
}
|
||||
public UmsService() {
|
||||
// 커넥션 풀 설정: 매번 소켓을 열고 닫지 않고 재사용함
|
||||
HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
|
||||
.setMaxConnTotal(100) // 전체 최대 커넥션 수
|
||||
.setMaxConnPerRoute(20) // 호스트당 최대 커넥션 수
|
||||
.setConnectionTimeToLive(TimeValue.ofMinutes(3)) // TTL
|
||||
.setValidateAfterInactivity(TimeValue.ofSeconds(5)) // 🔥 중요
|
||||
.build();
|
||||
|
||||
try {
|
||||
ValidationUtil.validateOrThrow(payload);
|
||||
} catch (Exception ex) {
|
||||
logger.debug(String.format("UMS Request payload validation failed - %s", payload));
|
||||
throw ex;
|
||||
}
|
||||
this.httpClient = HttpClients.custom()
|
||||
.setConnectionManager(cm)
|
||||
.evictExpiredConnections() // 만료 제거
|
||||
.evictIdleConnections(TimeValue.ofSeconds(20)) // 20초 idle 제거
|
||||
.build();
|
||||
}
|
||||
|
||||
return call(payload);
|
||||
}
|
||||
public UmsCallResult send(UmsRequestPayload payload) throws Exception {
|
||||
if (payload.getContent() == null) {
|
||||
throw new IllegalArgumentException("content is null");
|
||||
}
|
||||
|
||||
private CloseableHttpClient createHttpClient() {
|
||||
return HttpClients.createDefault();
|
||||
}
|
||||
try {
|
||||
ValidationUtil.validateOrThrow(payload);
|
||||
} catch (Exception ex) {
|
||||
logger.debug(String.format("UMS Request payload validation failed - %s", payload));
|
||||
throw ex;
|
||||
}
|
||||
|
||||
private Future<UmsCallResult> call(UmsRequestPayload requestPayload) throws Exception {
|
||||
return call(payload);
|
||||
}
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
String json = Jsons.GSON.toJson(requestPayload);
|
||||
|
||||
String host = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_HOST, UMS_URL);
|
||||
String url = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_URL, SEND_URL);
|
||||
String apiKey = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_API_KEY, API_KEY);
|
||||
private UmsCallResult call(UmsRequestPayload requestPayload) throws Exception {
|
||||
// 1. 프로퍼티 로드
|
||||
PropManager prop = PropManager.getInstance();
|
||||
String host = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_HOST, DEFAULT_UMS_URL);
|
||||
String uri = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_URL, DEFAULT_SEND_URI);
|
||||
String apiKey = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_API_KEY, DEFAULT_API_KEY);
|
||||
long connectionTimeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_CONNECTION_TIMEOUT, "3000"));
|
||||
long timeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_TIMEOUT, "3000"));
|
||||
// 2. 요청 생성
|
||||
HttpPost httpPost = new HttpPost(host + uri);
|
||||
httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, apiKey));
|
||||
|
||||
String json = Jsons.GSON.toJson(requestPayload);
|
||||
httpPost.setEntity(EntityBuilder.create()
|
||||
.setText(json)
|
||||
.setContentType(ContentType.APPLICATION_JSON)
|
||||
.setContentEncoding("UTF-8")
|
||||
.build());
|
||||
|
||||
HttpPost httpPost = new HttpPost(host + url);
|
||||
httpPost.setHeader("Content-Type", CONTENT_TYPE);
|
||||
httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, apiKey));
|
||||
httpPost.setEntity(EntityBuilder.create().setText(json).setContentType(ContentType.APPLICATION_JSON).build());
|
||||
// 3. 타임아웃 설정 (설정파일 값 적용)
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setConnectTimeout(Timeout.ofMilliseconds(connectionTimeoutMs))
|
||||
.setResponseTimeout(Timeout.ofMilliseconds(timeoutMs))
|
||||
.build();
|
||||
httpPost.setConfig(config);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
try {
|
||||
logger.debug("Header - {}", httpPost.getHeader("Content-Type"));
|
||||
logger.debug("Header - {}", httpPost.getHeader("Authorization"));
|
||||
logger.debug("Request Body : {}",
|
||||
StreamUtils.copyToString(httpPost.getEntity().getContent(), Charset.defaultCharset()));
|
||||
} catch (ProtocolException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("UMS Request to: {}", host + uri);
|
||||
logger.debug("UMS Request Body: {}", json);
|
||||
}
|
||||
|
||||
httpPost.setConfig(RequestConfig.custom().setConnectTimeout(Timeout.ofSeconds(3))
|
||||
.setResponseTimeout(Timeout.ofSeconds(3)).build());
|
||||
Future<UmsCallResult> future;
|
||||
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||
future = executor.submit(() -> {
|
||||
return httpClient.execute(httpPost, res -> {
|
||||
try {
|
||||
UmsCallResult result;
|
||||
String body = EntityUtils.toString(res.getEntity());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Response - {}", body);
|
||||
}
|
||||
result = Jsons.GSON.fromJson(body, UmsCallResult.class);
|
||||
result.setUmsMessageId(requestPayload.getMessageIdentityNo());
|
||||
result.setSuccess(true);
|
||||
return result;
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.error("UMS Call error(JSON Syntax)", e);
|
||||
return UmsCallResult.builder().umsMessageId(requestPayload.getMessageIdentityNo())
|
||||
.isSuccess(false).throwable(e).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("UMS Call error", e);
|
||||
return UmsCallResult.builder().umsMessageId(requestPayload.getMessageIdentityNo())
|
||||
.isSuccess(false).throwable(e).build();
|
||||
} finally {
|
||||
logger.debug("Response status - {}", res.getCode());
|
||||
// 4. 실행 (HttpClient 재사용)
|
||||
try {
|
||||
return httpClient.execute(httpPost, response -> {
|
||||
String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("UMS Response Status: {}", response.getCode());
|
||||
logger.debug("UMS Response Body: {}", body);
|
||||
}
|
||||
|
||||
if (res.getCode() != 200) {
|
||||
Arrays.asList(res.getHeaders()).forEach(o -> {
|
||||
logger.warn("[Header] {}: {}", o.getName(), o.getValue());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
UmsCallResult result = Jsons.GSON.fromJson(body, UmsCallResult.class);
|
||||
result.setUmsMessageId(requestPayload.getMessageIdentityNo());
|
||||
|
||||
// HTTP 200인 경우만 성공으로 간주 (필요에 따라 조정)
|
||||
result.setSuccess(response.getCode() == 200);
|
||||
|
||||
if (response.getCode() != 200) {
|
||||
logger.warn("UMS Call failed with status: {}", response.getCode());
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("UMS call exception: " + e.getMessage(), e);
|
||||
return UmsCallResult.builder()
|
||||
.umsMessageId(requestPayload.getMessageIdentityNo())
|
||||
.isSuccess(false)
|
||||
.throwable(e)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
return future;
|
||||
} catch (Exception e) {
|
||||
logger.error("UMS call exception", e);
|
||||
throw new Exception("UMS call failed", e);
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
try {
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
logger.info("UMS HttpClient closed.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Error closing UMS HttpClient", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user