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