|
@@ -1,17 +1,26 @@
|
|
|
package com.evps.comm.server.scheduler;
|
|
package com.evps.comm.server.scheduler;
|
|
|
|
|
|
|
|
|
|
+import com.evps.comm.server.config.ApplicationConfig;
|
|
|
import com.evps.comm.server.config.TraceConfig;
|
|
import com.evps.comm.server.config.TraceConfig;
|
|
|
import com.evps.comm.server.repository.ApplicationRepository;
|
|
import com.evps.comm.server.repository.ApplicationRepository;
|
|
|
import com.evps.comm.server.service.EvpsServiceManagerService;
|
|
import com.evps.comm.server.service.EvpsServiceManagerService;
|
|
|
import com.evps.comm.server.service.UnitSystService;
|
|
import com.evps.comm.server.service.UnitSystService;
|
|
|
|
|
+import com.evps.common.utils.SystemHealth;
|
|
|
|
|
+import com.zaxxer.hikari.HikariDataSource;
|
|
|
|
|
+import com.zaxxer.hikari.HikariPoolMXBean;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.springframework.scheduling.annotation.Async;
|
|
|
|
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
import javax.annotation.PreDestroy;
|
|
import javax.annotation.PreDestroy;
|
|
|
|
|
+import java.lang.management.ManagementFactory;
|
|
|
|
|
+import java.lang.management.ThreadInfo;
|
|
|
|
|
+import java.lang.management.ThreadMXBean;
|
|
|
|
|
+import java.text.DecimalFormat;
|
|
|
|
|
+import java.util.EnumMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
@RequiredArgsConstructor
|
|
@RequiredArgsConstructor
|
|
@@ -20,41 +29,54 @@ import javax.annotation.PreDestroy;
|
|
|
public class ApplicationScheduler {
|
|
public class ApplicationScheduler {
|
|
|
|
|
|
|
|
private final TraceConfig traceConfig;
|
|
private final TraceConfig traceConfig;
|
|
|
|
|
+ private final ApplicationConfig config;
|
|
|
private final UnitSystService unitSystService;
|
|
private final UnitSystService unitSystService;
|
|
|
private final ApplicationRepository applicationRepository;
|
|
private final ApplicationRepository applicationRepository;
|
|
|
private final EvpsServiceManagerService evpsServiceManagerService;
|
|
private final EvpsServiceManagerService evpsServiceManagerService;
|
|
|
|
|
|
|
|
|
|
+ private final HikariDataSource dataSource;
|
|
|
|
|
+ private final Map<Thread.State, Integer> stateCountMap = new EnumMap<>(Thread.State.class);
|
|
|
|
|
+ private final SystemHealth systemHealth = new SystemHealth();
|
|
|
|
|
+ private final DecimalFormat df = new DecimalFormat("#.##");
|
|
|
|
|
+
|
|
|
@PreDestroy
|
|
@PreDestroy
|
|
|
public void onShutDown() {
|
|
public void onShutDown() {
|
|
|
log.info("ApplicationScheduler.onShutDown: Shutting down...");
|
|
log.info("ApplicationScheduler.onShutDown: Shutting down...");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// @ScheduleElapsed
|
|
|
|
|
- @Async
|
|
|
|
|
@Scheduled(cron = "0 * * * * *")
|
|
@Scheduled(cron = "0 * * * * *")
|
|
|
public void updateProcessState() {
|
|
public void updateProcessState() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ this.systemHealth.checkHealth(false);
|
|
|
|
|
+ loggingHealthCheck();
|
|
|
|
|
+
|
|
|
|
|
+ double cpuUsage = this.systemHealth.getCpuUsage();
|
|
|
|
|
+ if (cpuUsage > this.config.getCpuLimits()) {
|
|
|
|
|
+// ApplicationRepository.processState.setErrDesc("CPU 사용율이 너무 높음: " + String.format("%.2f", cpuUsage));
|
|
|
|
|
+ log.warn("[SKIP] ApplicationScheduler.updateProcessState: High CPU Usage, Limit({} %), Current({} %), Schedule Job SKIP...",
|
|
|
|
|
+ this.config.getCpuLimits(), String.format("%.2f", cpuUsage));
|
|
|
|
|
+ loggingThreads();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("ApplicationScheduler.updateProcessState: System Health Check Exception {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
this.unitSystService.updateUnitSystStts();
|
|
this.unitSystService.updateUnitSystStts();
|
|
|
}
|
|
}
|
|
|
catch(Exception e) {
|
|
catch(Exception e) {
|
|
|
log.error("ApplicationScheduler.updateProcessState: Exception {}", e.getMessage());
|
|
log.error("ApplicationScheduler.updateProcessState: Exception {}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- // @ScheduleElapsed
|
|
|
|
|
- @Async
|
|
|
|
|
- @Scheduled(cron = "30 * * * * *") // 1분주기 작업 실행
|
|
|
|
|
- public void loadTraceConfig() {
|
|
|
|
|
try {
|
|
try {
|
|
|
this.traceConfig.loadTraceInfo();
|
|
this.traceConfig.loadTraceInfo();
|
|
|
}
|
|
}
|
|
|
catch(Exception e) {
|
|
catch(Exception e) {
|
|
|
- log.error("ApplicationScheduler.loadTraceConfig: Exception {}", e.getMessage());
|
|
|
|
|
|
|
+ log.error("ApplicationScheduler.loadTraceInfo: Exception {}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // @ScheduleElapsed
|
|
|
|
|
- @Async
|
|
|
|
|
@Scheduled(cron = "0/30 * * * * *")
|
|
@Scheduled(cron = "0/30 * * * * *")
|
|
|
public void serviceMangerSchedule() {
|
|
public void serviceMangerSchedule() {
|
|
|
try {
|
|
try {
|
|
@@ -65,8 +87,6 @@ public class ApplicationScheduler {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// @ScheduleElapsed
|
|
|
|
|
- @Async
|
|
|
|
|
@Scheduled(cron = "20 * * * * *") // 1분주기 작업 실행
|
|
@Scheduled(cron = "20 * * * * *") // 1분주기 작업 실행
|
|
|
public void reportCenterSessions() {
|
|
public void reportCenterSessions() {
|
|
|
try {
|
|
try {
|
|
@@ -77,8 +97,6 @@ public class ApplicationScheduler {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// @ScheduleElapsed
|
|
|
|
|
- @Async
|
|
|
|
|
@Scheduled(cron = "10 0/5 * * * *") // 5분주기 작업 실행
|
|
@Scheduled(cron = "10 0/5 * * * *") // 5분주기 작업 실행
|
|
|
public void loadBaseDatabase() {
|
|
public void loadBaseDatabase() {
|
|
|
try {
|
|
try {
|
|
@@ -89,4 +107,68 @@ public class ApplicationScheduler {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void loggingHealthCheck() {
|
|
|
|
|
+ log.info("----------------------------------------------------------------------------------------------------------");
|
|
|
|
|
+ loggingSystemHealth();
|
|
|
|
|
+ logSessionStatus();
|
|
|
|
|
+ loggingThreadState();
|
|
|
|
|
+ log.info("----------------------------------------------------------------------------------------------------------");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void loggingSystemHealth() {
|
|
|
|
|
+ double loadAvg = this.systemHealth.getLoadAverage();
|
|
|
|
|
+ String loadAvgStr = (loadAvg < 0) ? "N/A" : this.df.format(loadAvg);
|
|
|
|
|
+ log.info("SYSTEM HEALTH: CPU {} Cores[{} %, LoadAvg({})], Memory[{} %, Used({} MB), Max({} MB)], Threads[{}, Peak({})], GC[{}, {} ms]",
|
|
|
|
|
+ this.systemHealth.getCpuCores(),
|
|
|
|
|
+ this.df.format(this.systemHealth.getCpuUsage()),
|
|
|
|
|
+ loadAvgStr,
|
|
|
|
|
+ this.df.format(this.systemHealth.getMemUsage()),
|
|
|
|
|
+ this.systemHealth.getUsedMemory(),
|
|
|
|
|
+ this.systemHealth.getMaxMemory(),
|
|
|
|
|
+ this.systemHealth.getThreadCount(),
|
|
|
|
|
+ this.systemHealth.getPeakThreadCount(),
|
|
|
|
|
+ this.systemHealth.getGcCount(),
|
|
|
|
|
+ this.systemHealth.getGcTime());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void logSessionStatus() {
|
|
|
|
|
+ HikariPoolMXBean poolStats = this.dataSource.getHikariPoolMXBean();
|
|
|
|
|
+ int totalConnections = poolStats.getTotalConnections();
|
|
|
|
|
+ int activeConnections = poolStats.getActiveConnections();
|
|
|
|
|
+ int idleConnections = poolStats.getIdleConnections();
|
|
|
|
|
+ int threadsAwaiting = poolStats.getThreadsAwaitingConnection();
|
|
|
|
|
+ log.info(" DB SESSION: Total: {}, Active: {}, Idle: {}, Waiting: {}",
|
|
|
|
|
+ totalConnections, activeConnections, idleConnections, threadsAwaiting);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void loggingThreadState() {
|
|
|
|
|
+ ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
|
|
|
|
+ ThreadInfo[] infos = threadBean.dumpAllThreads(false, false);
|
|
|
|
|
+ this.stateCountMap.clear();
|
|
|
|
|
+ for (ThreadInfo info : infos) {
|
|
|
|
|
+ Thread.State state = info.getThreadState();
|
|
|
|
|
+ this.stateCountMap.put(state, this.stateCountMap.getOrDefault(state, 0) + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ for (Map.Entry<Thread.State, Integer> entry : stateCountMap.entrySet()) {
|
|
|
|
|
+ sb.append(String.format("%s(%d), ", entry.getKey().name(), entry.getValue()));
|
|
|
|
|
+ }
|
|
|
|
|
+ // 마지막 쉼표 제거
|
|
|
|
|
+ if (sb.length() > 0) {
|
|
|
|
|
+ sb.setLength(sb.length() - 2);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info(" THREAD STATE: {}", sb.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void loggingThreads() {
|
|
|
|
|
+ ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
|
|
|
|
+ ThreadInfo[] infos = threadBean.dumpAllThreads(false, false);
|
|
|
|
|
+ this.stateCountMap.clear();
|
|
|
|
|
+ for (ThreadInfo info : infos) {
|
|
|
|
|
+ Thread.State state = info.getThreadState();
|
|
|
|
|
+ this.stateCountMap.put(state, this.stateCountMap.getOrDefault(state, 0) + 1);
|
|
|
|
|
+ log.info(" [" + info.getThreadId() + "] " + info.getThreadName() + " - " + info.getThreadState());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|