ApplicationScheduler.java 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package com.evps.comm.server.scheduler;
  2. import com.evps.comm.server.config.ApplicationConfig;
  3. import com.evps.comm.server.config.TraceConfig;
  4. import com.evps.comm.server.repository.ApplicationRepository;
  5. import com.evps.comm.server.service.EvpsServiceManagerService;
  6. import com.evps.comm.server.service.UnitSystService;
  7. import com.evps.common.utils.SystemHealth;
  8. import com.zaxxer.hikari.HikariDataSource;
  9. import com.zaxxer.hikari.HikariPoolMXBean;
  10. import lombok.RequiredArgsConstructor;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.springframework.scheduling.annotation.EnableScheduling;
  13. import org.springframework.scheduling.annotation.Scheduled;
  14. import org.springframework.stereotype.Component;
  15. import javax.annotation.PreDestroy;
  16. import java.lang.management.ManagementFactory;
  17. import java.lang.management.ThreadInfo;
  18. import java.lang.management.ThreadMXBean;
  19. import java.text.DecimalFormat;
  20. import java.util.EnumMap;
  21. import java.util.Map;
  22. @Slf4j
  23. @RequiredArgsConstructor
  24. @EnableScheduling
  25. @Component
  26. public class ApplicationScheduler {
  27. private final TraceConfig traceConfig;
  28. private final ApplicationConfig config;
  29. private final UnitSystService unitSystService;
  30. private final ApplicationRepository applicationRepository;
  31. private final EvpsServiceManagerService evpsServiceManagerService;
  32. private final HikariDataSource dataSource;
  33. private final Map<Thread.State, Integer> stateCountMap = new EnumMap<>(Thread.State.class);
  34. private final SystemHealth systemHealth = new SystemHealth();
  35. private final DecimalFormat df = new DecimalFormat("#.##");
  36. @PreDestroy
  37. public void onShutDown() {
  38. log.info("ApplicationScheduler.onShutDown: Shutting down...");
  39. }
  40. @Scheduled(cron = "0 * * * * *")
  41. public void updateProcessState() {
  42. try {
  43. this.systemHealth.checkHealth(false);
  44. loggingHealthCheck();
  45. double cpuUsage = this.systemHealth.getCpuUsage();
  46. if (cpuUsage > this.config.getCpuLimits()) {
  47. // ApplicationRepository.processState.setErrDesc("CPU 사용율이 너무 높음: " + String.format("%.2f", cpuUsage));
  48. log.warn("[SKIP] ApplicationScheduler.updateProcessState: High CPU Usage, Limit({} %), Current({} %), Schedule Job SKIP...",
  49. this.config.getCpuLimits(), String.format("%.2f", cpuUsage));
  50. loggingThreads();
  51. return;
  52. }
  53. } catch (Exception e) {
  54. log.error("ApplicationScheduler.updateProcessState: System Health Check Exception {}", e.getMessage());
  55. }
  56. try {
  57. this.unitSystService.updateUnitSystStts();
  58. }
  59. catch(Exception e) {
  60. log.error("ApplicationScheduler.updateProcessState: Exception {}", e.getMessage());
  61. }
  62. try {
  63. this.traceConfig.loadTraceInfo();
  64. }
  65. catch(Exception e) {
  66. log.error("ApplicationScheduler.loadTraceInfo: Exception {}", e.getMessage());
  67. }
  68. }
  69. @Scheduled(cron = "0/30 * * * * *")
  70. public void serviceMangerSchedule() {
  71. try {
  72. this.evpsServiceManagerService.checkServiceTimeout();
  73. }
  74. catch(Exception e) {
  75. log.error("ApplicationScheduler.serviceMangerSchedule: Exception {}", e.getMessage());
  76. }
  77. }
  78. @Scheduled(cron = "20 * * * * *") // 1분주기 작업 실행
  79. public void reportCenterSessions() {
  80. try {
  81. this.applicationRepository.reportCenterSessions();
  82. }
  83. catch(Exception e) {
  84. log.error("ApplicationScheduler.reportCenterSessions: Exception {}", e.getMessage());
  85. }
  86. }
  87. @Scheduled(cron = "10 0/5 * * * *") // 5분주기 작업 실행
  88. public void loadBaseDatabase() {
  89. try {
  90. this.applicationRepository.loadDb();
  91. }
  92. catch(Exception e) {
  93. log.error("ApplicationScheduler.loadBaseDatabase: Exception {}", e.getMessage());
  94. }
  95. }
  96. private void loggingHealthCheck() {
  97. log.info("----------------------------------------------------------------------------------------------------------");
  98. loggingSystemHealth();
  99. logSessionStatus();
  100. loggingThreadState();
  101. log.info("----------------------------------------------------------------------------------------------------------");
  102. }
  103. private void loggingSystemHealth() {
  104. double loadAvg = this.systemHealth.getLoadAverage();
  105. String loadAvgStr = (loadAvg < 0) ? "N/A" : this.df.format(loadAvg);
  106. log.info("SYSTEM HEALTH: CPU {} Cores[{} %, LoadAvg({})], Memory[{} %, Used({} MB), Max({} MB)], Threads[{}, Peak({})], GC(T/R)[{}/{} ms]",
  107. this.systemHealth.getCpuCores(),
  108. this.df.format(this.systemHealth.getCpuUsage()),
  109. loadAvgStr,
  110. this.df.format(this.systemHealth.getMemUsage()),
  111. this.systemHealth.getUsedMemory(),
  112. this.systemHealth.getMaxMemory(),
  113. this.systemHealth.getThreadCount(),
  114. this.systemHealth.getPeakThreadCount(),
  115. this.systemHealth.getGcTotalAvgTime(),
  116. this.systemHealth.getGcRecentAvgTime());
  117. }
  118. private void logSessionStatus() {
  119. HikariPoolMXBean poolStats = this.dataSource.getHikariPoolMXBean();
  120. int totalConnections = poolStats.getTotalConnections();
  121. int activeConnections = poolStats.getActiveConnections();
  122. int idleConnections = poolStats.getIdleConnections();
  123. int threadsAwaiting = poolStats.getThreadsAwaitingConnection();
  124. log.info(" DB SESSION: Total: {}, Active: {}, Idle: {}, Waiting: {}",
  125. totalConnections, activeConnections, idleConnections, threadsAwaiting);
  126. }
  127. private void loggingThreadState() {
  128. ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
  129. ThreadInfo[] infos = threadBean.dumpAllThreads(false, false);
  130. this.stateCountMap.clear();
  131. for (ThreadInfo info : infos) {
  132. Thread.State state = info.getThreadState();
  133. this.stateCountMap.put(state, this.stateCountMap.getOrDefault(state, 0) + 1);
  134. }
  135. StringBuilder sb = new StringBuilder();
  136. for (Map.Entry<Thread.State, Integer> entry : stateCountMap.entrySet()) {
  137. sb.append(String.format("%s(%d), ", entry.getKey().name(), entry.getValue()));
  138. }
  139. // 마지막 쉼표 제거
  140. if (sb.length() > 0) {
  141. sb.setLength(sb.length() - 2);
  142. }
  143. log.info(" THREAD STATE: {}", sb.toString());
  144. }
  145. private void loggingThreads() {
  146. ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
  147. ThreadInfo[] infos = threadBean.dumpAllThreads(false, false);
  148. this.stateCountMap.clear();
  149. for (ThreadInfo info : infos) {
  150. Thread.State state = info.getThreadState();
  151. this.stateCountMap.put(state, this.stateCountMap.getOrDefault(state, 0) + 1);
  152. log.info(" [" + info.getThreadId() + "] " + info.getThreadName() + " - " + info.getThreadState());
  153. }
  154. }
  155. }