Bladeren bron

refactoring

HANTE 1 maand geleden
bovenliggende
commit
1a43394738
43 gewijzigde bestanden met toevoegingen van 1185 en 765 verwijderingen
  1. 2 0
      conf/tsi-comm-server-trace.cfg
  2. 9 9
      pom.xml
  3. 47 15
      src/main/java/com/tsi/comm/server/TsiCommServerApplication.java
  4. 21 17
      src/main/java/com/tsi/comm/server/config/TraceConfig.java
  5. 7 22
      src/main/java/com/tsi/comm/server/config/TsiCvimServerConfig.java
  6. 5 3
      src/main/java/com/tsi/comm/server/config/TsiKafkaProducerConfig.java
  7. 0 1
      src/main/java/com/tsi/comm/server/config/TsiSchedulingConfig.java
  8. 3 6
      src/main/java/com/tsi/comm/server/config/TsiThreadPoolConfig.java
  9. 11 12
      src/main/java/com/tsi/comm/server/kafka/KafkaConsumerService.java
  10. 68 77
      src/main/java/com/tsi/comm/server/kafka/KafkaProducerService.java
  11. 12 13
      src/main/java/com/tsi/comm/server/kafka/TsiKafkaConsumerWorker.java
  12. 12 17
      src/main/java/com/tsi/comm/server/mongo/config/MongoDbConfiguration.java
  13. 4 4
      src/main/java/com/tsi/comm/server/mongo/dto/TcsNodeStatus.java
  14. 4 6
      src/main/java/com/tsi/comm/server/mongo/repository/TsiNodeStatusRepository.java
  15. 0 5
      src/main/java/com/tsi/comm/server/mybatis/MybatisConfig.java
  16. 3 0
      src/main/java/com/tsi/comm/server/mybatis/TsiDatabaseMapper.java
  17. 38 38
      src/main/java/com/tsi/comm/server/mybatis/TsiDatabaseService.java
  18. 3 0
      src/main/java/com/tsi/comm/server/mybatis/vo/AbstractDbmsVo.java
  19. 18 0
      src/main/java/com/tsi/comm/server/mybatis/vo/NodeIpAddrVo.java
  20. 2 0
      src/main/java/com/tsi/comm/server/process/AbstractTsiCvimProcess.java
  21. 3 0
      src/main/java/com/tsi/comm/server/process/AbstractTsiCvimWorker.java
  22. 49 24
      src/main/java/com/tsi/comm/server/process/dbms/TsiCvimDbmsProcess.java
  23. 59 24
      src/main/java/com/tsi/comm/server/process/dbms/TsiCvimDbmsWorker.java
  24. 51 19
      src/main/java/com/tsi/comm/server/process/logging/TsiCvimLoggingProcess.java
  25. 93 63
      src/main/java/com/tsi/comm/server/process/logging/TsiCvimLoggingWorker.java
  26. 49 22
      src/main/java/com/tsi/comm/server/process/packet/TsiCvimPacketProcess.java
  27. 102 49
      src/main/java/com/tsi/comm/server/process/packet/TsiCvimPacketWorker.java
  28. 5 2
      src/main/java/com/tsi/comm/server/protocol/TsiCpuDisconnected.java
  29. 6 2
      src/main/java/com/tsi/comm/server/protocol/TsiCpuPacket.java
  30. 10 0
      src/main/java/com/tsi/comm/server/repository/ApplicationRepository.java
  31. 56 33
      src/main/java/com/tsi/comm/server/repository/TsiAlarmManager.java
  32. 7 17
      src/main/java/com/tsi/comm/server/repository/TsiNodeAddManager.java
  33. 7 148
      src/main/java/com/tsi/comm/server/repository/TsiNodeManager.java
  34. 221 0
      src/main/java/com/tsi/comm/server/repository/TsiReportManager.java
  35. 8 23
      src/main/java/com/tsi/comm/server/repository/TsiSessionManager.java
  36. 24 37
      src/main/java/com/tsi/comm/server/repository/TsiTpmsManager.java
  37. 53 16
      src/main/java/com/tsi/comm/server/scheduler/TsiCommScheduler.java
  38. 43 14
      src/main/java/com/tsi/comm/server/tcp/codec/CvimServerByteBufMessageDecoder.java
  39. 14 8
      src/main/java/com/tsi/comm/server/tcp/handler/CvimServerInboundMessageHandler.java
  40. 3 1
      src/main/java/com/tsi/comm/server/vo/TsiNodeVo.java
  41. 5 3
      src/main/resources/application.yml
  42. 40 15
      src/main/resources/logback-spring.xml
  43. 8 0
      src/main/resources/mybatis/mapper/tsi-comm-server.xml

+ 2 - 0
conf/tsi-comm-server-trace.cfg

@@ -1,2 +1,4 @@
+#queue-report=false
+#session-report=false
 #DUMP=1610121022,...
 DUMP=1610121022

+ 9 - 9
pom.xml

@@ -69,15 +69,15 @@
             <version>2.7.0</version>
         </dependency>-->
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-mongodb</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mongodb</groupId>
-            <artifactId>mongo-java-driver</artifactId>
-            <version>3.12.7</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.boot</groupId>-->
+<!--            <artifactId>spring-boot-starter-data-mongodb</artifactId>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.mongodb</groupId>-->
+<!--            <artifactId>mongo-java-driver</artifactId>-->
+<!--            <version>3.12.7</version>-->
+<!--        </dependency>-->
 
         <dependency>
             <groupId>org.mariadb.jdbc</groupId>

+ 47 - 15
src/main/java/com/tsi/comm/server/TsiCommServerApplication.java

@@ -7,7 +7,10 @@ import com.tsi.comm.server.kafka.KafkaProducerService;
 import com.tsi.comm.server.mybatis.TsiDatabaseService;
 import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
 import com.tsi.comm.server.mybatis.vo.AlarmOccrVo;
-import com.tsi.comm.server.repository.TsiAlarmManager;
+import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
+import com.tsi.comm.server.process.logging.TsiCvimLoggingProcess;
+import com.tsi.comm.server.process.packet.TsiCvimPacketProcess;
+import com.tsi.comm.server.repository.ApplicationRepository;
 import com.tsi.comm.server.repository.TsiSessionManager;
 import com.tsi.comm.server.tcp.TsiCvimServer;
 import com.tsi.comm.server.vo.TsiAlarmConfigVo;
@@ -60,22 +63,38 @@ public class TsiCommServerApplication implements CommandLineRunner, ApplicationL
         log.info("************************************************************************************");
 
         TsiCvimServerConfig config = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
-        TsiAlarmManager.getInstance().getProcessStateVo().setProcessId(applicationName + "-" + config.getServerId());
+
+        ApplicationRepository.processStateVo.setProcessId(applicationName + "-" + config.getServerId());
+//        TsiAlarmManager alarmManager = (TsiAlarmManager) AppUtils.getBean(TsiAlarmManager.class);
+//        alarmManager.getProcessStateVo().setProcessId(applicationName + "-" + config.getServerId());
 
         TsiDatabaseService tsiDatabaseService = (TsiDatabaseService) AppUtils.getBean(TsiDatabaseService.class);
-        tsiDatabaseService.initDatabase();
-        tsiDatabaseService.loadDatabase();
+        tsiDatabaseService.init();
+
+        TsiCvimLoggingProcess loggingProcess = (TsiCvimLoggingProcess) AppUtils.getBean(TsiCvimLoggingProcess.class);
+        loggingProcess.start();
+
+        TsiCvimDbmsProcess dbmsProcess = (TsiCvimDbmsProcess) AppUtils.getBean(TsiCvimDbmsProcess.class);
+        dbmsProcess.start();
+
+        TsiCvimPacketProcess packetProcess = (TsiCvimPacketProcess) AppUtils.getBean(TsiCvimPacketProcess.class);
+        packetProcess.start();
+
+        TsiSessionManager sessionManager = (TsiSessionManager) AppUtils.getBean(TsiSessionManager.class);
+        sessionManager.start();
 
-        TsiSessionManager.getInstance().start();
         TsiCvimServer cvimServer = (TsiCvimServer)AppUtils.getBean(TsiCvimServer.class);
         cvimServer.run();
 
         KafkaConsumerService kafkaConsumerService = (KafkaConsumerService) AppUtils.getBean(KafkaConsumerService.class);
         kafkaConsumerService.start();
 
-        // 시스템 시작 알람 이력 저장
+        KafkaProducerService kafkaProducerService = (KafkaProducerService) AppUtils.getBean(KafkaProducerService.class);
+        kafkaProducerService.start();
+
+        config.setStartup(true);
         try {
-//            TsiDatabaseService tsiDatabaseService = (TsiDatabaseService) AppUtils.getBean(TsiDatabaseService.class);
+            // 시스템 시작 알람 이력 저장
             AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
             alarm.setAlarmCode(TsiAlarmConfigVo.SYS_00);
             alarm.setAlarmTarget(applicationName);
@@ -83,31 +102,44 @@ public class TsiCommServerApplication implements CommandLineRunner, ApplicationL
             tsiDatabaseService.insertAlarmOccrHs(alarm);
             tsiDatabaseService.updateProcessState(0);
         }
-        catch(Exception e) {
-        }
+        catch(Exception e) { }
     }
 
     @Override
     public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
         SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-        TsiSessionManager.getInstance().stop();
+        int serverId = 0;
+        try {
+            TsiCvimServerConfig config = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
+            config.setStartup(false);
+            serverId = config.getServerId();
+        } catch (Exception e) { }
+
+        try {
+            TsiSessionManager sessionManager = (TsiSessionManager) AppUtils.getBean(TsiSessionManager.class);
+            sessionManager.stop();
+        } catch (Exception e) { }
 
-        TsiCvimServer cvimServer = (TsiCvimServer)AppUtils.getBean(TsiCvimServer.class);
         try {
+            TsiCvimServer cvimServer = (TsiCvimServer)AppUtils.getBean(TsiCvimServer.class);
             cvimServer.stop();
         } catch (Exception e) { }
 
-        KafkaProducerService kafkaProducerService = (KafkaProducerService)AppUtils.getBean(KafkaProducerService.class);
         try {
+            KafkaProducerService kafkaProducerService = (KafkaProducerService)AppUtils.getBean(KafkaProducerService.class);
             kafkaProducerService.shutdown();
         } catch (Exception e) { }
 
-        TsiDatabaseService tsiDatabaseService = (TsiDatabaseService)AppUtils.getBean(TsiDatabaseService.class);
         try {
-            TsiCvimServerConfig config = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
+            KafkaConsumerService kafkaConsumerService = (KafkaConsumerService)AppUtils.getBean(KafkaConsumerService.class);
+            kafkaConsumerService.shutdown();
+        } catch (Exception e) { }
+
+        try {
+            TsiDatabaseService tsiDatabaseService = (TsiDatabaseService)AppUtils.getBean(TsiDatabaseService.class);
             // 노드 통신상태 Off 초기화
-            tsiDatabaseService.updateNodeStatusTerm(config.getServerId());
+            tsiDatabaseService.updateNodeStatusTerm(serverId);
 
             // 시스템 종료 알람 이력 저장
             AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);

+ 21 - 17
src/main/java/com/tsi/comm/server/config/TraceConfig.java

@@ -22,31 +22,33 @@ import java.util.Properties;
 @Component
 public class TraceConfig {
 
+    private final TsiNodeManager nodeManager;
+
+    private boolean queueReport = true;
+    private boolean sessionReport = true;
 
     private Properties getProperties() {
         String workingDir = System.getProperty("user.dir");
+        Properties props = new Properties();
         try {
             FileInputStream in = new FileInputStream(workingDir + "/conf/tsi-comm-server-trace.cfg");
-            Properties props = new Properties();
             props.load(in);
             in.close();
-            return props;
         }
         catch(Exception e) {
             log.error("{}.getTraceFileInputStream: Exception1: {}", this.getClass().getSimpleName(), e.toString());
-            return null;
-        }
-    }
-
-    private int getIntNo(String intNo) {
-        try {
-            return Integer.parseInt(intNo.trim());
-        }
-        catch (NumberFormatException e) {
-            return -1;
         }
+        return props;
     }
 
+//    private int getIntNo(String intNo) {
+//        try {
+//            return Integer.parseInt(intNo.trim());
+//        }
+//        catch (NumberFormatException e) {
+//            return -1;
+//        }
+//    }
 
     private long getNodeId(String nodeId) {
         try {
@@ -60,22 +62,24 @@ public class TraceConfig {
     public void loadTraceInfo() {
         try {
             Properties props = getProperties();
-            if (props == null) {
-                return;
-            }
 
-            TsiNodeManager.getInstance().initDump();
+            this.nodeManager.initDump();
 
             String dumps  = props.getProperty("DUMP",  "").trim();
             if (!dumps.isEmpty()) {
                 List<String> regionCds = StringUtils.split(dumps, ",");
                 regionCds.forEach(id -> {
-                    TsiNodeVo node = TsiNodeManager.getInstance().get(getNodeId(id.trim()));
+                    TsiNodeVo node = this.nodeManager.get(getNodeId(id.trim()));
                     if (node != null) {
                         node.setDump(true);
                     }
                 });
             }
+            String queue  = props.getProperty("queue-report",  "true").trim();
+            this.queueReport = queue.equalsIgnoreCase("true");
+
+            String session  = props.getProperty("session-report",  "true").trim();
+            this.sessionReport = session.equalsIgnoreCase("true");
         }
         catch(Exception e) {
             log.error("{}.loadDebugInfo: Exception2: {}", this.getClass().getSimpleName(), e.toString());

+ 7 - 22
src/main/java/com/tsi/comm/server/config/TsiCvimServerConfig.java

@@ -1,7 +1,8 @@
 package com.tsi.comm.server.config;
 
 import com.tsi.app.common.xnet.NettyServerConfig;
-import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
@@ -9,27 +10,24 @@ import org.springframework.stereotype.Component;
 import javax.annotation.PostConstruct;
 
 @Slf4j
-@Data
+@Getter
+@Setter
 @Component
 @ConfigurationProperties(prefix = "application.cvim-server")
 public class TsiCvimServerConfig extends NettyServerConfig {
 
     private int serverId = 0;
-    private int maxConnection = 0;
-    private boolean loggingThread = false;
     private int packetWorkers = 0;
     private int loggingWorkers = 0;
     private int dbmsWorkers = 0;
     private boolean checkPacket = true;
+    private boolean startup = false;
 
     @PostConstruct
     private void init() {
 
         configure();
 
-        if (this.maxConnection == 0) {
-            this.maxConnection = 10000;
-        }
         if (this.packetWorkers == 0) {
             this.packetWorkers = Runtime.getRuntime().availableProcessors() / 2;
             if (this.packetWorkers == 0) this.packetWorkers = 16;
@@ -42,30 +40,17 @@ public class TsiCvimServerConfig extends NettyServerConfig {
             this.dbmsWorkers = Runtime.getRuntime().availableProcessors() / 4;
             if (this.dbmsWorkers == 0) this.dbmsWorkers = 8;
         }
-        if (getReaderIdleTimeSeconds() <= 5) {
+        if (getReaderIdleTimeSeconds() < 5) {
             setReaderIdleTimeSeconds(5);
         }
 
         log.info("[{}] -------------------------", this.getClass().getSimpleName());
         log.info("[{}]              serverId: {}", this.getClass().getSimpleName(), this.serverId);
-        log.info("[{}]         maxConnection: {}", this.getClass().getSimpleName(), this.maxConnection);
-        log.info("[{}]         loggingThread: {}", this.getClass().getSimpleName(), this.loggingThread);
         log.info("[{}]         packetWorkers: {}", this.getClass().getSimpleName(), this.packetWorkers);
         log.info("[{}]        loggingWorkers: {}", this.getClass().getSimpleName(), this.loggingWorkers);
+        log.info("[{}]           dbmsWorkers: {}", this.getClass().getSimpleName(), this.dbmsWorkers);
         log.info("[{}]           checkPacket: {}", this.getClass().getSimpleName(), this.checkPacket);
         log.info("{}", super.toString());
     }
 
-    public int getQueueSize() {
-        int qSize = 10000;
-        if (this.maxConnection == 0)
-            qSize = 10000;
-        else if (this.maxConnection < 5000)
-            qSize = 5000;
-        else {
-            if (this.maxConnection > qSize)
-                qSize = this.maxConnection;
-        }
-        return qSize;
-    }
 }

+ 5 - 3
src/main/java/com/tsi/comm/server/config/TsiKafkaProducerConfig.java

@@ -1,7 +1,8 @@
 package com.tsi.comm.server.config;
 
 import com.tsi.app.common.xnet.NetUtils;
-import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerConfig;
 import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -14,7 +15,8 @@ import java.util.List;
 import java.util.Map;
 
 @Slf4j
-@Data
+@Getter
+@Setter
 @Component
 @ConfigurationProperties(prefix = "application.kafka.producer")
 public class TsiKafkaProducerConfig {
@@ -29,7 +31,7 @@ public class TsiKafkaProducerConfig {
     private boolean multiConnect = false;
     private String bootstrapServers;
 
-    public List<Map<String, String>> props = new ArrayList<Map<String, String>>();
+    private List<Map<String, String>> props = new ArrayList<>();
 
     private String cvimServers = "";
     private String nodeServers = "";

+ 0 - 1
src/main/java/com/tsi/comm/server/config/TsiSchedulingConfig.java

@@ -22,7 +22,6 @@ public class TsiSchedulingConfig implements SchedulingConfigurer {
 
     @PostConstruct
     private void init() {
-        log.info("[{}] ------------", this.getClass().getSimpleName());
         if (this.poolCore == 0) {
             log.warn("[{}] poolCore size set as default: {} EA.", this.getClass().getSimpleName(), this.poolCore);
             this.poolCore = 10;

+ 3 - 6
src/main/java/com/tsi/comm/server/config/TsiThreadPoolConfig.java

@@ -24,19 +24,16 @@ public class TsiThreadPoolConfig extends AsyncConfigurerSupport {
 
     @PostConstruct
     private void init() {
-        log.info("[{}] -------------------------", this.getClass().getSimpleName());
-        log.info("[{}]   availableProcessors: {}", this.getClass().getSimpleName(), this.MAX_CORE);
         if (this.MAX_CORE < 8) {
             this.MAX_CORE = 16;
         }
 
-        log.info("[{}]              MAX_CORE: {}", this.getClass().getSimpleName(), this.MAX_CORE);
-        log.info("[{}] threadPoolCore before: {}", this.getClass().getSimpleName(), this.poolCore);
-
         if (this.poolCore < this.MAX_CORE) {
             this.poolCore = this.MAX_CORE;
         }
-        log.info("[{}] threadPoolCore .after: {}", this.getClass().getSimpleName(), this.poolCore);
+        log.info("[{}]   availableProcessors: {}", this.getClass().getSimpleName(), this.MAX_CORE);
+        log.info("[{}]              MAX_CORE: {}", this.getClass().getSimpleName(), this.MAX_CORE);
+        log.info("[{}]        threadPoolCore: {}", this.getClass().getSimpleName(), this.poolCore);
         log.info("[{}]          CorePoolSize: {} EA.", this.getClass().getSimpleName(), this.poolCore);
         log.info("[{}]           MaxPoolSize: {} EA.", this.getClass().getSimpleName(), getMaxPoolSize());
         log.info("[{}]         QueueCapacity: {} EA.", this.getClass().getSimpleName(), getQueueCapacity());

+ 11 - 12
src/main/java/com/tsi/comm/server/kafka/KafkaConsumerService.java

@@ -2,10 +2,13 @@ package com.tsi.comm.server.kafka;
 
 import com.tsi.comm.server.config.TsiCvimServerConfig;
 import com.tsi.comm.server.config.TsiKafkaProducerConfig;
+import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
+import com.tsi.comm.server.repository.TsiTpmsManager;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.Consumer;
 import org.apache.kafka.common.TopicPartition;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.kafka.core.ConsumerFactory;
 import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
 import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
@@ -13,7 +16,6 @@ import org.springframework.kafka.listener.ConsumerAwareRebalanceListener;
 import org.springframework.kafka.listener.ContainerProperties;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
 import java.util.Collection;
 
 @Slf4j
@@ -23,14 +25,10 @@ public class KafkaConsumerService {
 
     private final TsiCvimServerConfig config;
     private final TsiKafkaProducerConfig producerConfig;
+    private final TsiTpmsManager tpmsManager;
+    private final TsiCvimDbmsProcess dbmsProcess;
 
-    private ConcurrentMessageListenerContainer<String, Long> kafkaListenerContainer;
-
-    @PostConstruct
-    void init() {
-        log.info("[{}] ------------------", this.getClass().getSimpleName());
-        start();
-    }
+    private ConcurrentMessageListenerContainer<String, Long> kafkaListenerContainer = null;
 
     public void start() {
 
@@ -46,16 +44,16 @@ public class KafkaConsumerService {
         containerProperties.setGroupId(this.producerConfig.getGroupId());
         containerProperties.setPollTimeout(5000);
         //containerProperties.setAckMode(ContainerProperties.AckMode.MANUAL);
-        containerProperties.setMessageListener(new TsiKafkaConsumerWorker());
+        containerProperties.setMessageListener(new TsiKafkaConsumerWorker(this.tpmsManager, this.dbmsProcess));
         containerProperties.setConsumerRebalanceListener(new ConsumerAwareRebalanceListener() {
             @Override
-            public void onPartitionsRevokedBeforeCommit(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+            public void onPartitionsRevokedBeforeCommit(@NotNull Consumer<?, ?> consumer, @NotNull Collection<TopicPartition> partitions) {
             }
             @Override
-            public void onPartitionsRevokedAfterCommit(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+            public void onPartitionsRevokedAfterCommit(@NotNull Consumer<?, ?> consumer, @NotNull Collection<TopicPartition> partitions) {
             }
             @Override
-            public void onPartitionsAssigned(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+            public void onPartitionsAssigned(@NotNull Consumer<?, ?> consumer, @NotNull Collection<TopicPartition> partitions) {
                 consumer.seekToEnd(partitions);
             }
         });
@@ -82,6 +80,7 @@ public class KafkaConsumerService {
             }
         }
         catch(Exception ignored) {
+            // Ignored exception during shutdown
         }
     }
 }

+ 68 - 77
src/main/java/com/tsi/comm/server/kafka/KafkaProducerService.java

@@ -11,29 +11,29 @@ import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
 import com.tsi.comm.server.repository.TsiAlarmManager;
 import com.tsi.comm.server.repository.TsiTpmsManager;
 import com.tsi.comm.server.vo.TsiAlarmConfigVo;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.kafka.clients.producer.Callback;
 import org.apache.kafka.clients.producer.ProducerConfig;
-import org.apache.kafka.clients.producer.RecordMetadata;
-import org.apache.kafka.common.PartitionInfo;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.kafka.core.KafkaTemplate;
 import org.springframework.kafka.support.SendResult;
 import org.springframework.stereotype.Service;
 import org.springframework.util.concurrent.ListenableFuture;
 import org.springframework.util.concurrent.ListenableFutureCallback;
 
-import javax.annotation.PostConstruct;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 @Slf4j
+@RequiredArgsConstructor
 @Service
 public class KafkaProducerService {
 
     private final TsiCvimServerConfig config;
     private final TsiKafkaProducerConfig producerConfig;
+    private final TsiAlarmManager alarmManager;
+    private final TsiTpmsManager tpmsManager;
     private final TsiCvimDbmsProcess dbmsProcess;
 
     private KafkaTemplate<String, byte[]> cvimProducer;
@@ -42,36 +42,27 @@ public class KafkaProducerService {
     private KafkaTemplate<String, Long> pingProducer;
 
 
-    //ProducerResultCallback callback;
-
-    public KafkaProducerService(TsiCvimServerConfig config, TsiKafkaProducerConfig producerConfig, TsiCvimDbmsProcess dbmsProcess) {
-        this.config = config;
-        this.producerConfig = producerConfig;
-        this.dbmsProcess = dbmsProcess;
-    }
-
-    @PostConstruct
-    void init() {
+    public void start() {
         //this.callback = new ProducerResultCallback();
 
         if (this.producerConfig.isMultiConnect()) {
             // 각각의 Producer 에 대하여 KafkaTemplate 를 생성해서 사용한다.
             if (this.producerConfig.isEnableCvim()) {
-                this.cvimProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getCvimServers(), this.producerConfig.props);
+                this.cvimProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getCvimServers(), this.producerConfig.getProps());
                 this.cvimProducer.setDefaultTopic(TsiKafkaProducerConfig.CVIM_RAW_TOPIC);
             }
             if (this.producerConfig.isEnableNode()) {
-                this.nodeProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getNodeServers(), this.producerConfig.props);
+                this.nodeProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getNodeServers(), this.producerConfig.getProps());
             }
             if (this.producerConfig.isEnableTest()) {
-                this.testProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getTestServers(), this.producerConfig.props);
+                this.testProducer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getTestServers(), this.producerConfig.getProps());
                 this.testProducer.setDefaultTopic(TsiKafkaProducerConfig.TEST_TOPIC);
             }
         }
         else {
             // 하나의 Producer KafkaTemplate 로 데이터를 전송하는 경우
             // 동일한 KafkaTemplate 를 사용한다.
-            KafkaTemplate<String, byte[]> producer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getBootstrapServers(), this.producerConfig.props);
+            KafkaTemplate<String, byte[]> producer = KafkaProducerFactory.createByteArrayTemplate(this.producerConfig.getBootstrapServers(), this.producerConfig.getProps());
             if (this.producerConfig.isEnableCvim()) {
                 this.cvimProducer = producer;
             }
@@ -126,33 +117,33 @@ public class KafkaProducerService {
             }
         }
         catch(Exception e) {
-
+            // 로그를 남기지 않고, 예외가 발생해도 무시한다.
         }
     }
-    public boolean initPartitions() {
-        try {
-            if (this.testProducer != null) {
-                List<PartitionInfo> partitionInfos = this.testProducer.partitionsFor(TsiKafkaProducerConfig.TEST_TOPIC);
-                log.info("{} partitions: {}", TsiKafkaProducerConfig.TEST_TOPIC, partitionInfos);
-            }
-        }
-        catch(Exception e) {
-            log.error("Request partitionFor {}: {}", TsiKafkaProducerConfig.TEST_TOPIC, e.toString());
-            return false;
-        }
-
-        try {
-            if (this.cvimProducer != null) {
-                List<PartitionInfo> partitionInfos = this.cvimProducer.partitionsFor(TsiKafkaProducerConfig.CVIM_RAW_TOPIC);
-                log.info("{} partitions: {}", TsiKafkaProducerConfig.CVIM_RAW_TOPIC, partitionInfos);
-            }
-        }
-        catch (Exception e) {
-            log.error("Request partitionFor {}: {}", TsiKafkaProducerConfig.CVIM_RAW_TOPIC, e.toString());
-            return false;
-        }
-        return true;
-    }
+//    public boolean initPartitions() {
+//        try {
+//            if (this.testProducer != null) {
+//                List<PartitionInfo> partitionInfos = this.testProducer.partitionsFor(TsiKafkaProducerConfig.TEST_TOPIC);
+//                log.info("{} partitions: {}", TsiKafkaProducerConfig.TEST_TOPIC, partitionInfos);
+//            }
+//        }
+//        catch(Exception e) {
+//            log.error("Request partitionFor {}: {}", TsiKafkaProducerConfig.TEST_TOPIC, e.toString());
+//            return false;
+//        }
+//
+//        try {
+//            if (this.cvimProducer != null) {
+//                List<PartitionInfo> partitionInfos = this.cvimProducer.partitionsFor(TsiKafkaProducerConfig.CVIM_RAW_TOPIC);
+//                log.info("{} partitions: {}", TsiKafkaProducerConfig.CVIM_RAW_TOPIC, partitionInfos);
+//            }
+//        }
+//        catch (Exception e) {
+//            log.error("Request partitionFor {}: {}", TsiKafkaProducerConfig.CVIM_RAW_TOPIC, e.toString());
+//            return false;
+//        }
+//        return true;
+//    }
 
     public void sendPing() {
         if (this.pingProducer == null ) {
@@ -161,9 +152,9 @@ public class KafkaProducerService {
         }
 
         long sendNanoTime = System.nanoTime();
-        TsiTpmsManager.getInstance().getKafkaTransVo().setSendNanoTime(sendNanoTime);   // nano seconds
-        TsiTpmsManager.getInstance().getKafkaTransVo().setSendTm(0);                    // micro seconds
-        TsiTpmsManager.getInstance().getKafkaTransVo().setRecvTm(0);                    // micro seconds
+        tpmsManager.getKafkaTransVo().setSendNanoTime(sendNanoTime);   // nano seconds
+        tpmsManager.getKafkaTransVo().setSendTm(0);                    // micro seconds
+        tpmsManager.getKafkaTransVo().setRecvTm(0);                    // micro seconds
 
         ListenableFuture<SendResult<String, Long>> future =  this.pingProducer.sendDefault("key", sendNanoTime);
         future.addCallback(new ListenableFutureCallback<SendResult<String, Long>>() {
@@ -172,12 +163,12 @@ public class KafkaProducerService {
             public void onSuccess(SendResult<String, Long> result) {
                 long recvNanoTime = System.nanoTime();
                 long sendTime = TimeUnit.MICROSECONDS.convert(Math.abs(recvNanoTime - sendNanoTime), TimeUnit.NANOSECONDS);
-                TsiTpmsManager.getInstance().getKafkaTransVo().setSendTm(sendTime);
+                tpmsManager.getKafkaTransVo().setSendTm(sendTime);
                 log.info("send ping success: {}, {}", sendNanoTime, TimeUtils.elapsedTimeStr(recvNanoTime - sendNanoTime));
 
                 // 카프카 전송 지연 알람 저장
-                if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.KAFKA_02)) {
-                    TsiAlarmConfigVo alarmConfig = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.KAFKA_02);
+                if (alarmManager.checkAlarm(TsiAlarmConfigVo.KAFKA_02)) {
+                    TsiAlarmConfigVo alarmConfig = alarmManager.get(TsiAlarmConfigVo.KAFKA_02);
                     if (alarmConfig != null && sendTime > alarmConfig.getValue()) {
                         AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
                         alarm.setAlarmCode(TsiAlarmConfigVo.KAFKA_02);
@@ -188,11 +179,11 @@ public class KafkaProducerService {
                 }
             }
             @Override
-            public void onFailure(Throwable ex) {
+            public void onFailure(@NotNull Throwable ex) {
                 long recvNanoTime = System.nanoTime();
-                TsiTpmsManager.getInstance().getKafkaTransVo().setSendNanoTime(0);
+                tpmsManager.getKafkaTransVo().setSendNanoTime(0);
                 KafkaTransVo stat = new KafkaTransVo(AbstractDbmsVo.DBMS_KAFKA_TRANS_HS);
-                stat.setHostName(TsiTpmsManager.getInstance().getKafkaTransVo().getHostName());
+                stat.setHostName(tpmsManager.getKafkaTransVo().getHostName());
                 stat.setStatus(0);
                 stat.setSendTm(TimeUnit.MICROSECONDS.convert(Math.abs(recvNanoTime - sendNanoTime), TimeUnit.NANOSECONDS));
                 stat.setRecvTm(0);
@@ -200,10 +191,10 @@ public class KafkaProducerService {
                 log.error("send ping failed: {}, {}, {}", sendNanoTime, TimeUtils.elapsedTimeStr(recvNanoTime - sendNanoTime), ex.getMessage());
 
                 // 카프카 전송 오류 알람 저장
-                String value = "Send Failed";
-                if (ex != null) {
-                    value = ex.getMessage().substring(0, 99);
-                }
+                String value = ex.getMessage().substring(0, 99);
+                //if (ex != null) {
+                //    value = ex.getMessage().substring(0, 99);
+                //}
                 AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
                 alarm.setAlarmCode(TsiAlarmConfigVo.KAFKA_01);
                 alarm.setAlarmTarget(producerConfig.getBootstrapServers());
@@ -253,25 +244,25 @@ public class KafkaProducerService {
         }
     }
 
-    protected void send(KafkaTemplate<String, byte[]> kafka, String topic, String key, byte[] data) {
-        try {
-            kafka.send(topic, key, data);
-        }
-        catch(Exception e) {
-            log.error("kafka.send: {}, Exception: {}", topic, e.getMessage());
-        }
-    }
+//    protected void send(KafkaTemplate<String, byte[]> kafka, String topic, String key, byte[] data) {
+//        try {
+//            kafka.send(topic, key, data);
+//        }
+//        catch(Exception e) {
+//            log.error("kafka.send: {}, Exception: {}", topic, e.getMessage());
+//        }
+//    }
 
-    private static class ProducerResultCallback implements Callback {
-        @Override
-        public void onCompletion(RecordMetadata recordMetadata, Exception e) {
-            if (e != null) {
-                log.error("Error while producing message to topic: {}, {}", recordMetadata, e.toString());
-            }
-            else {
-                String message = String.format("sent message to topic:%s partition:%s  offset:%s", recordMetadata.topic(), recordMetadata.partition(), recordMetadata.offset());
-                System.out.println(message);
-            }
-        }
-    }
+//    private static class ProducerResultCallback implements Callback {
+//        @Override
+//        public void onCompletion(RecordMetadata recordMetadata, Exception e) {
+//            if (e != null) {
+//                log.error("Error while producing message to topic: {}, {}", recordMetadata, e.toString());
+//            }
+//            else {
+//                String message = String.format("sent message to topic:%s partition:%s  offset:%s", recordMetadata.topic(), recordMetadata.partition(), recordMetadata.offset());
+//                log.error(message);
+//            }
+//        }
+//    }
 }

+ 12 - 13
src/main/java/com/tsi/comm/server/kafka/TsiKafkaConsumerWorker.java

@@ -1,37 +1,36 @@
 package com.tsi.comm.server.kafka;
 
-import com.tsi.app.common.app.AppUtils;
 import com.tsi.app.common.utils.TimeUtils;
 import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
 import com.tsi.comm.server.mybatis.vo.KafkaTransVo;
 import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
 import com.tsi.comm.server.repository.TsiTpmsManager;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.kafka.listener.MessageListener;
 import org.springframework.kafka.support.Acknowledgment;
 
 import java.util.concurrent.TimeUnit;
 
 @Slf4j
+@RequiredArgsConstructor
 public class TsiKafkaConsumerWorker implements MessageListener<String, Long> {
 
+    private final TsiTpmsManager tpmsManager;
     private final TsiCvimDbmsProcess dbmsProcess;
 
-    public TsiKafkaConsumerWorker() {
-        this.dbmsProcess = (TsiCvimDbmsProcess) AppUtils.getBean(TsiCvimDbmsProcess.class);
-    }
-
     @Override
-    public void onMessage(ConsumerRecord<String, Long> record) {
-        Long sendNanoTime = record.value();
+    public void onMessage(ConsumerRecord<String, Long> consumerRecord) {
+        Long sendNanoTime = consumerRecord.value();
         Long recvNanoTime = System.nanoTime();
 
         KafkaTransVo stat = new KafkaTransVo(AbstractDbmsVo.DBMS_KAFKA_TRANS_HS);
-        stat.setHostName(TsiTpmsManager.getInstance().getKafkaTransVo().getHostName());
+        stat.setHostName(this.tpmsManager.getKafkaTransVo().getHostName());
         stat.setStatus(1);
-        if (TsiTpmsManager.getInstance().getKafkaTransVo().getSendNanoTime() == sendNanoTime) {
-            stat.setSendTm(TsiTpmsManager.getInstance().getKafkaTransVo().getSendTm());
+        if (this.tpmsManager.getKafkaTransVo().getSendNanoTime() == sendNanoTime) {
+            stat.setSendTm(this.tpmsManager.getKafkaTransVo().getSendTm());
             stat.setRecvTm(TimeUnit.MICROSECONDS.convert(Math.abs(recvNanoTime - sendNanoTime), TimeUnit.NANOSECONDS));
         }
         else {
@@ -44,14 +43,14 @@ public class TsiKafkaConsumerWorker implements MessageListener<String, Long> {
     }
 
     @Override
-    public void onMessage(ConsumerRecord<String, Long> record, Acknowledgment acknowledgment) {
+    public void onMessage(@NotNull ConsumerRecord<String, Long> consumerRecord, Acknowledgment acknowledgment) {
         try {
-            Long sendNanoTime = record.value();
+            Long sendNanoTime = consumerRecord.value();
             Long recvNanoTime = System.nanoTime();
             log.info("recv ping success, ack: {}, {}", sendNanoTime, TimeUtils.elapsedTimeStr(recvNanoTime - sendNanoTime));
             //acknowledgment.acknowledge();
         } catch (Exception e) {
-            log.error("onMessage:" + e.getMessage());
+            log.error("KafkaConsumerWorker.onMessage:{}", e.getMessage());
         }
     }
 

+ 12 - 17
src/main/java/com/tsi/comm/server/mongo/config/MongoDbConfiguration.java

@@ -1,25 +1,20 @@
 package com.tsi.comm.server.mongo.config;
 
-import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
-import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
-import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
-
-import javax.annotation.PostConstruct;
 
 @Profile("mongodb")
-@Configuration
+//@Configuration
 public class MongoDbConfiguration {
 
-    private final MappingMongoConverter mappingMongoConverter;
-
-    public MongoDbConfiguration(MappingMongoConverter mappingMongoConverter) {
-        this.mappingMongoConverter = mappingMongoConverter;
-    }
-
-    // remove _class
-    @PostConstruct
-    public void setUpMongoEscapeCharacterConversion() {
-        mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
-    }
+//    private final MappingMongoConverter mappingMongoConverter;
+//
+//    public MongoDbConfiguration(MappingMongoConverter mappingMongoConverter) {
+//        this.mappingMongoConverter = mappingMongoConverter;
+//    }
+//
+//    // remove _class
+//    @PostConstruct
+//    public void setUpMongoEscapeCharacterConversion() {
+//        mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
+//    }
 }

+ 4 - 4
src/main/java/com/tsi/comm/server/mongo/dto/TcsNodeStatus.java

@@ -7,18 +7,18 @@ import com.tsi.app.common.utils.StringUtils;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.ToString;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
+//import org.springframework.data.annotation.Id;
+//import org.springframework.data.mongodb.core.mapping.Document;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @Getter
 @ToString
-@Document(collection = "tb_tcs_node_status")
+//@Document(collection = "tb_tcs_node_status")
 public class TcsNodeStatus {
 
-    @Id
+//    @Id
     private Long _id;
     private Long nodeId;
     private boolean isConnect;

+ 4 - 6
src/main/java/com/tsi/comm/server/mongo/repository/TsiNodeStatusRepository.java

@@ -1,13 +1,11 @@
 package com.tsi.comm.server.mongo.repository;
 
-import com.tsi.comm.server.mongo.dto.TcsNodeStatus;
-import org.bson.types.ObjectId;
 import org.springframework.context.annotation.Profile;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.stereotype.Repository;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.mongodb.repository.MongoRepository;
 
 @Profile("mongodb")
-@Repository
-public interface TsiNodeStatusRepository extends MongoRepository<TcsNodeStatus, ObjectId> {
+//@Repository
+public interface TsiNodeStatusRepository { //extends MongoRepository<TcsNodeStatus, ObjectId> {
 
 }

+ 0 - 5
src/main/java/com/tsi/comm/server/mybatis/MybatisConfig.java

@@ -15,7 +15,6 @@ import org.springframework.context.annotation.Primary;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
-import javax.annotation.PostConstruct;
 import javax.sql.DataSource;
 
 @Configuration
@@ -25,10 +24,6 @@ public class MybatisConfig {
     @Value("${spring.datasource.mybatis.mapper-locations:classpath:mybatis/mapper/**/*.xml}")
     String mapperLocations;
 
-    @PostConstruct
-    private void init() {
-    }
-
     @Primary
     @Bean(name="dataSource")
     @ConfigurationProperties(prefix="spring.datasource.mybatis")

+ 3 - 0
src/main/java/com/tsi/comm/server/mybatis/TsiDatabaseMapper.java

@@ -14,6 +14,9 @@ public interface TsiDatabaseMapper {
 
     List<NodeVo> getNodeInfoList();
     List<NodeAddVo> getNodeAddInfoList();
+
+    int updateNodeIpAddr(@Param("node") NodeIpAddrVo node);
+
     int insertNodeStatusInitialize();
     int updateNodeStatusTerm(@Param("serverId") Integer serverId);
 

+ 38 - 38
src/main/java/com/tsi/comm/server/mybatis/TsiDatabaseService.java

@@ -2,6 +2,7 @@ package com.tsi.comm.server.mybatis;
 
 import com.tsi.app.common.utils.TimeUtils;
 import com.tsi.comm.server.mybatis.vo.*;
+import com.tsi.comm.server.repository.ApplicationRepository;
 import com.tsi.comm.server.repository.TsiAlarmManager;
 import com.tsi.comm.server.repository.TsiNodeAddManager;
 import com.tsi.comm.server.repository.TsiNodeManager;
@@ -15,7 +16,6 @@ import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
 import java.util.List;
 
 @Slf4j
@@ -25,21 +25,22 @@ import java.util.List;
 @Service
 public class TsiDatabaseService {
 
-    private final TsiDatabaseMapper tsiDatabaseMapper;
+    private final TsiDatabaseMapper databaseMapper;
+    private final TsiNodeManager nodeManager;
+    private final TsiAlarmManager alarmManager;
+    private final TsiNodeAddManager nodeAddManager;
 
-    @PostConstruct
-    void init() {
-//        initDatabase();
-//        loadDatabase();
+    public void init() {
+        initDatabase();
+        loadDatabase();
     }
 
     public void loadAlarmConfig() {
-        String TAG = "loadAlarmConfig";
         long startTime = System.nanoTime();
 
-        List<AlarmConfigVo> objLists = this.tsiDatabaseMapper.getAlarmConfig();
+        List<AlarmConfigVo> objLists = this.databaseMapper.getAlarmConfig();
         for (AlarmConfigVo obj : objLists) {
-            TsiAlarmConfigVo alarm = TsiAlarmManager.getInstance().get(obj.getAlarmCode());
+            TsiAlarmConfigVo alarm = this.alarmManager.get(obj.getAlarmCode());
             if (alarm != null) {
                 alarm.setDesc(obj.getDesc());
                 alarm.setValue(obj.getValue());
@@ -51,15 +52,15 @@ public class TsiDatabaseService {
                 alarm.setDesc(obj.getDesc());
                 alarm.setValue(obj.getValue());
                 alarm.setUseYn(obj.getUseYn().equals("Y"));
-                TsiAlarmManager.getInstance().put(obj.getAlarmCode(), alarm);
+                this.alarmManager.put(obj.getAlarmCode(), alarm);
             }
         }
 
-        log.info("{}: ..end. {}/{} EA. {}", TAG, objLists.size(), TsiAlarmManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
+        log.info("loadAlarmConfig: ..end. {}/{} EA. {}", objLists.size(), this.alarmManager.size(), TimeUtils.elapsedTime(startTime));
     }
 
     public void initDatabase() {
-        int result = this.tsiDatabaseMapper.insertNodeStatusInitialize();
+        int result = this.databaseMapper.insertNodeStatusInitialize();
         //updateNodeStatusTerm();
         log.info("init database: {} EA", result);
     }
@@ -71,19 +72,18 @@ public class TsiDatabaseService {
     }
 
     private void loadTsiNode() {
-        String TAG = "loadTsiNode";
         long startTime = System.nanoTime();
 
-        TsiNodeManager.getInstance().beforeLoading();
+        this.nodeManager.beforeLoading();
 
         boolean installed;
         TsiNodeVo node;
 
         int idx = 0;
-        List<NodeVo> objLists = this.tsiDatabaseMapper.getNodeInfoList();
+        List<NodeVo> objLists = this.databaseMapper.getNodeInfoList();
         for (NodeVo obj : objLists) {
             installed = obj.getUseYn().equals("Y");
-            node = TsiNodeManager.getInstance().get(obj.getNodeId());
+            node = this.nodeManager.get(obj.getNodeId());
             if (node != null) {
                 node.setCheckInstalled(installed);
                 node.setSendTest(obj.getTestYn().equals("Y"));
@@ -92,41 +92,41 @@ public class TsiDatabaseService {
                 node.setRegistered(true);
             }
             else {
-                node = new TsiNodeVo(obj.getNodeId(), obj.getTestYn().equals("Y"), obj.getNodeYn().equals("Y"), obj.getCvimYn().equals("Y"));
+                node = new TsiNodeVo(obj.getNodeId(), obj.getIpAddr(), obj.getTestYn().equals("Y"), obj.getNodeYn().equals("Y"), obj.getCvimYn().equals("Y"));
                 node.setRegistered(true);
                 node.setCheckInstalled(installed);
-                TsiNodeManager.getInstance().put(obj.getNodeId(), node);
+                this.nodeManager.put(obj.getNodeId(), node);
             }
             node.setIdx(idx++);  // 인덱스 설정
             //int hash = Long.hashCode(obj.getNodeId()); // 해시코드 생성, 필요시 사용
             //int idx = Math.abs(hash % 9);
         }
 
-        TsiNodeManager.getInstance().afterLoading();
+        this.nodeManager.afterLoading();
 
-        log.info("{}: ..end. {}/{} EA. {}", TAG, objLists.size(), TsiNodeManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
+        log.info("loadTsiNode: ..end. {}/{} EA. {}", objLists.size(), this.nodeManager.size(), TimeUtils.elapsedTime(startTime));
     }
 
     private void loadTsiNodeAdd() {
-        String TAG = "loadTsiNodeAdd";
         long startTime = System.nanoTime();
 
         // 연등지 노드정보 조회
         long originNodeId;
         TsiNodeVo orgTsiNodeVo;
 
-        List<NodeAddVo> objLists = this.tsiDatabaseMapper.getNodeAddInfoList();
+        List<NodeAddVo> objLists = this.databaseMapper.getNodeAddInfoList();
         for (NodeAddVo obj : objLists) {
             originNodeId = obj.getOriginNodeId();
-            orgTsiNodeVo = TsiNodeManager.getInstance().get(originNodeId);
+            orgTsiNodeVo = this.nodeManager.get(originNodeId);
             if (orgTsiNodeVo == null) {
                 // 등록안된 Original Node 를 참조하는 경우
                 log.error("Not found origin_node_id: {}", originNodeId);
-                orgTsiNodeVo = new TsiNodeVo(originNodeId, true, true, true);
+                String ipAddr = "0.0.0.0";
+                orgTsiNodeVo = new TsiNodeVo(originNodeId, ipAddr, true, true, true);
                 orgTsiNodeVo.setCheckInstalled(true);
                 orgTsiNodeVo.setRegistered(false);
                 orgTsiNodeVo.setAddNodeEnabled(true);
-                TsiNodeManager.getInstance().put(originNodeId, orgTsiNodeVo);   // 신규로 추가해 준다
+                this.nodeManager.put(originNodeId, orgTsiNodeVo);   // 신규로 추가해 준다
             }
             else {
                 orgTsiNodeVo.setAddNodeEnabled(true);
@@ -141,14 +141,14 @@ public class TsiDatabaseService {
                 Long nodeId = nodeAddDetailVo.getNodeId();
 
                 TsiNodeAddDetailVo tsiNodeAddDetailVo = new TsiNodeAddDetailVo();
-                TsiNodeVo addNodeVo = TsiNodeManager.getInstance().get(nodeId);
+                TsiNodeVo addNodeVo = this.nodeManager.get(nodeId);
                 if (addNodeVo == null) {
                     // 등록안된 Node 인 경우
                     log.error("Not found add_node_id: {}", nodeId);
-                    addNodeVo = new TsiNodeVo(originNodeId, orgTsiNodeVo.isSendTest(), orgTsiNodeVo.isSendNode(), orgTsiNodeVo.isSendCvim());
+                    addNodeVo = new TsiNodeVo(originNodeId, orgTsiNodeVo.getIpAddr(), orgTsiNodeVo.isSendTest(), orgTsiNodeVo.isSendNode(), orgTsiNodeVo.isSendCvim());
                     addNodeVo.setCheckInstalled(true);
                     addNodeVo.setRegistered(false);
-                    TsiNodeManager.getInstance().put(nodeId, addNodeVo);    // 신규로 추가해 준다
+                    this.nodeManager.put(nodeId, addNodeVo);    // 신규로 추가해 준다
                 }
 
                 tsiNodeAddDetailVo.setNodeId(nodeId);
@@ -158,27 +158,27 @@ public class TsiDatabaseService {
                 tsiNodeAddDetailVo.setNodeObj(addNodeVo);
 
                 tsiNodeAddVo.getAddNodeMap().put(tsiNodeAddDetailVo.getOriginDirCode()*1000 + tsiNodeAddDetailVo.getAddNodeOrder(), tsiNodeAddDetailVo);
-                if (tsiNodeAddDetailVo.getNodeObj() != null) {
-                    //log.error("    {}, {}, {}", nodeAddVo.getOriginNodeId(), nodeId, detailVo.getNodeId());
-                }
+//                if (tsiNodeAddDetailVo.getNodeObj() != null) {
+//                    //log.error("    {}, {}, {}", nodeAddVo.getOriginNodeId(), nodeId, detailVo.getNodeId());
+//                }
             }
 
             orgTsiNodeVo.setTsiNodeAddVo(tsiNodeAddVo);
 
-            TsiNodeAddManager.getInstance().put(tsiNodeAddVo.getOriginNodeId(), tsiNodeAddVo);
+            this.nodeAddManager.put(tsiNodeAddVo.getOriginNodeId(), tsiNodeAddVo);
         }
 
-        log.info("{}: ..end. {} EA. {}", TAG, TsiNodeAddManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
+        log.info("loadTsiNodeAdd: ..end. {} EA. {}", this.nodeAddManager.size(), TimeUtils.elapsedTime(startTime));
     }
 
     public void updateNodeStatusTerm(int serverId) {
-        int result = this.tsiDatabaseMapper.updateNodeStatusTerm(serverId);
+        int result = this.databaseMapper.updateNodeStatusTerm(serverId);
         log.info("update node status term: {} EA", result);
     }
     public int insertAlarmOccrHs(AlarmOccrVo vo) {
         int res = 0;
         try {
-            res = this.tsiDatabaseMapper.insertAlarmOccrHs(vo);
+            res = this.databaseMapper.insertAlarmOccrHs(vo);
         }
         catch(Exception e) {
             log.error("{}", e.getMessage());
@@ -189,13 +189,13 @@ public class TsiDatabaseService {
         int res = 0;
         try {
             if (flag == 0) {
-                res = this.tsiDatabaseMapper.updateProcessStatusStart(TsiAlarmManager.getInstance().getProcessStateVo());
+                res = this.databaseMapper.updateProcessStatusStart(ApplicationRepository.processStateVo);
             }
             else if (flag == 1) {
-                res = this.tsiDatabaseMapper.updateProcessStatusRun(TsiAlarmManager.getInstance().getProcessStateVo());
+                res = this.databaseMapper.updateProcessStatusRun(ApplicationRepository.processStateVo);
             }
             else {
-                res = this.tsiDatabaseMapper.updateProcessStatusStop(TsiAlarmManager.getInstance().getProcessStateVo());
+                res = this.databaseMapper.updateProcessStatusStop(ApplicationRepository.processStateVo);
             }
         }
         catch(Exception e) {

+ 3 - 0
src/main/java/com/tsi/comm/server/mybatis/vo/AbstractDbmsVo.java

@@ -15,12 +15,15 @@ public abstract class AbstractDbmsVo {
     public static final int DBMS_KAFKA_TRANS_HS = 3;
     public static final int DBMS_ALARM_OCCR_HS = 4;
     public static final int DBMS_PROCESS_STATE = 5;
+    public static final int DBMS_NODE_IP_UPDATE = 6;
 
     protected int dbmsType;
     protected String eventDt;
+    protected long createTime;
 
     public AbstractDbmsVo(int dbmsType) {
         this.dbmsType = dbmsType;
         this.eventDt = TimeUtils.getCurrentTimeString();
+        this.createTime = System.nanoTime();
     }
 }

+ 18 - 0
src/main/java/com/tsi/comm/server/mybatis/vo/NodeIpAddrVo.java

@@ -0,0 +1,18 @@
+package com.tsi.comm.server.mybatis.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class NodeIpAddrVo extends AbstractDbmsVo {
+
+    private long nodeId;
+    private String ipAddr;
+
+    public NodeIpAddrVo(int dbmsType) {
+        super(dbmsType);
+    }
+}

+ 2 - 0
src/main/java/com/tsi/comm/server/process/AbstractTsiCvimProcess.java

@@ -1,10 +1,12 @@
 package com.tsi.comm.server.process;
 
 import com.tsi.app.common.utils.Counter;
+import lombok.Getter;
 
 import java.util.ArrayList;
 import java.util.List;
 
+@Getter
 public abstract class AbstractTsiCvimProcess {
 
     protected int workers;

+ 3 - 0
src/main/java/com/tsi/comm/server/process/AbstractTsiCvimWorker.java

@@ -1,5 +1,8 @@
 package com.tsi.comm.server.process;
 
+import lombok.Getter;
+
+@Getter
 public abstract class AbstractTsiCvimWorker {
 
     protected long avgTime = 0;

+ 49 - 24
src/main/java/com/tsi/comm/server/process/dbms/TsiCvimDbmsProcess.java

@@ -1,6 +1,5 @@
 package com.tsi.comm.server.process.dbms;
 
-import com.tsi.app.common.app.AppUtils;
 import com.tsi.comm.server.config.TsiCvimServerConfig;
 import com.tsi.comm.server.process.AbstractTsiCvimProcess;
 import com.tsi.comm.server.process.AbstractTsiCvimWorker;
@@ -10,7 +9,10 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
 @Getter
@@ -18,33 +20,45 @@ import javax.annotation.PostConstruct;
 @Service
 public class TsiCvimDbmsProcess extends AbstractTsiCvimProcess {
 
-    @PostConstruct
-    void init() {
-        ThreadGroup workerGroup = new ThreadGroup("dbmsProcess");
-        TsiCvimServerConfig tsiCvimServerConfig = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
+    private final TsiCvimServerConfig config;
+    private final TsiNodeManager nodeManager;
+    private ExecutorService executor = null;
 
-        this.workers = tsiCvimServerConfig.getDbmsWorkers();
-        if (this.workers <= 0) this.workers = 1;
-        int nodes = TsiNodeManager.getInstance().size();
-        int qSize = tsiCvimServerConfig.getQueueSize();
-        if (nodes > qSize) {
-            qSize = nodes;
+    public void start() {
+        final ThreadGroup workerGroup = new ThreadGroup("dbmsProcess");
+        this.workers = this.config.getDbmsWorkers();
+        int qSize = this.nodeManager.size();
+        if (this.workers == 1) {
+            qSize *= 2;
         }
-        qSize *= 4;
-        qSize /= this.workers;
-        qSize = 1000;
-        //this.workers = 1;
+
+        this.executor = Executors.newFixedThreadPool(this.workers, new ThreadFactory() {
+            private int count = 0;
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(workerGroup, r);
+                t.setName(String.format("dbsWorker-%02d.%02d", workers, ++count));
+                t.setDaemon(true);
+                return t;
+            }
+        });
+
         for (int ii = 0; ii < this.workers; ii++) {
             TsiCvimDbmsWorker dbmsWorker = new TsiCvimDbmsWorker(ii, qSize);
             this.workerList.add(dbmsWorker);
-            Thread worker = new Thread(workerGroup, dbmsWorker);
-            worker.setName(String.format("dbsWorker-%02d.%02d", this.workers, ii+1));
-            worker.setDaemon(true);
-            this.threadList.add(worker);
-        }
-        for (Thread worker : this.threadList) {
-            worker.start();
+            this.executor.submit(dbmsWorker); // 여기서 실행됨!
         }
+
+//        for (int ii = 0; ii < this.workers; ii++) {
+//            TsiCvimDbmsWorker dbmsWorker = new TsiCvimDbmsWorker(ii, qSize);
+//            this.workerList.add(dbmsWorker);
+//            Thread worker = new Thread(workerGroup, dbmsWorker);
+//            worker.setName(String.format("dbsWorker-%02d.%02d", this.workers, ii+1));
+//            worker.setDaemon(true);
+//            this.threadList.add(worker);
+//        }
+//        for (Thread worker : this.threadList) {
+//            worker.start();
+//        }
     }
 
     public boolean add(Object object, int idx) {
@@ -55,12 +69,23 @@ public class TsiCvimDbmsProcess extends AbstractTsiCvimProcess {
             offer = this.workerList.get(idx).add(object);
         }
         catch (Exception e) {
-            log.error("QUEUE_DATA.add: Exception: {}, {}", object.toString(), e.getMessage());
+            log.error("DbmsProcess: QUEUE_DATA.add: Exception: {}, {}", object.toString(), e.getMessage());
         }
         return offer;
     }
 
     public void stop() {
+        log.info("DbmsProcess Stopping...");
+        this.executor.shutdown();
+        try {
+            if (!this.executor.awaitTermination(3, TimeUnit.SECONDS)) {
+                this.executor.shutdownNow(); // 실행 중인 작업도 중단 시도
+            }
+        } catch (InterruptedException e) {
+            this.executor.shutdownNow();
+            Thread.currentThread().interrupt(); // 현재 스레드도 중단
+        }
+        log.info("DbmsProcess Stopped...");
     }
 
     public void report() {

+ 59 - 24
src/main/java/com/tsi/comm/server/process/dbms/TsiCvimDbmsWorker.java

@@ -6,11 +6,14 @@ import com.tsi.app.common.utils.TimeUtils;
 import com.tsi.comm.server.mybatis.TsiDatabaseMapper;
 import com.tsi.comm.server.mybatis.vo.*;
 import com.tsi.comm.server.process.AbstractTsiCvimWorker;
+import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
+@Getter
 public class TsiCvimDbmsWorker extends AbstractTsiCvimWorker implements Runnable {
 
     //private ConcurrentLinkedQueue<AbstractTsiPacket> DATA_QUEUE;
@@ -26,38 +29,62 @@ public class TsiCvimDbmsWorker extends AbstractTsiCvimWorker implements Runnable
 
     @Override
     public void run() {
-        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
-        while (true) {
-            try {
-                Object object = this.DATA_QUEUE.take();
-                if (object != null) {
-                    process(object);
-                }
-                else {
-                    Thread.yield();
+        log.info("DbmsWorker({}): {} Start. QSIZE: {}", this.idx, Thread.currentThread().getName(), this.qSize);
+        try {
+            while (!Thread.currentThread().isInterrupted()) {
+                try {
+                    Object object = this.DATA_QUEUE.poll(1, TimeUnit.SECONDS); // 인터럽트 감지 가능
+                    if (object != null) {
+                        process(object);
+                    } else {
+                        Thread.yield(); // 대기 중 CPU 양보
+                    }
+                } catch (InterruptedException ie) {
+                    log.warn("DbmsWorker({}): {} Interrupted. Exiting...", this.idx, Thread.currentThread().getName());
+                    Thread.currentThread().interrupt(); // 상태 복구
+                    break;
+                } catch (Exception e) {
+                    log.error("DbmsWorker({}): {} Exception: {}", this.idx, Thread.currentThread().getName(), e.getMessage());
                 }
             }
-            catch (Exception e) {
-                log.error("Exception(DbmsWorker while): {}", e.getMessage());
-            }
+        } finally {
+            log.info("DbmsWorker({}): {} Stopped.", this.idx, Thread.currentThread().getName());
         }
     }
 
+//    @Override
+//    public void run() {
+//        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
+//        while (true) {
+//            try {
+//                Object object = this.DATA_QUEUE.take();
+//                if (object != null) {
+//                    process(object);
+//                }
+//                else {
+//                    Thread.yield();
+//                }
+//            }
+//            catch (Exception e) {
+//                log.error("Exception(DbmsWorker while): {}", e.getMessage());
+//            }
+//        }
+//    }
+
     /*
      *  작업큐에 데이터 추가
      */
     public boolean add(Object object) {
         boolean offer = false;
         try {
-            //offer => full -> return
-            //add   => full -> wait
-            offer = this.DATA_QUEUE.offer(object);
+            offer = this.DATA_QUEUE.offer(object);  //offer => full -> return, add => full -> wait
             if (!offer) {
-                log.error("Dbms Queue.offer: {}/{}, {}, Queue Full: {} EA, {}, {}",
-                        object.getClass().getSimpleName(), this.DATA_QUEUE.size(), this.idx, this.qSize, object, Thread.currentThread().getName());
+                log.error("DbmsWorker({}): Queue.offer(Full): {}/{}/{}, {}, {}",
+                        this.idx, this.DATA_QUEUE.size(), this.qSize, this.DATA_QUEUE.remainingCapacity(),
+                        object, Thread.currentThread().getName());
             }
         } catch (Exception e) {
-            log.error("Dbms Queue.offer: Exception: {}, {}, {}", object.toString(), Thread.currentThread().getName(), e.getMessage());
+            log.error("DbmsWorker({}): Queue.offer: Exception: {}, {}, {}", this.idx, object.toString(), Thread.currentThread().getName(), e.getMessage());
         }
         return offer;
     }
@@ -91,16 +118,20 @@ public class TsiCvimDbmsWorker extends AbstractTsiCvimWorker implements Runnable
                     count = 1;
                     this.tsiDatabaseMapper.insertAlarmOccrHs((AlarmOccrVo)object);
                 }
+                else if (dbmsVo.getDbmsType() == AbstractDbmsVo.DBMS_NODE_IP_UPDATE) {
+                    job = "NodeIpAddr";
+                    count = 1;
+                    this.tsiDatabaseMapper.updateNodeIpAddr((NodeIpAddrVo)object);
+                }
             }
             catch (Exception e) {
-                log.error("{}, {}", job, dbmsVo);
-                log.error("{}", e.getMessage());
+                log.error("DbmsWorker.process: {}, {}, Exception: {}", job, dbmsVo, e.getMessage());
             }
+            calcProcessTime(dbmsVo.getCreateTime());
         }
         else {
-            log.error("Unknown Object Class: {}", object.getClass().getSimpleName());
+            log.error("DbmsWorker.process: Unknown Object Class: {}", object.getClass().getSimpleName());
         }
-
         if (elapsed.milliSeconds() > 500) {
             // 로그가 너무 많아 일정 시간 이상 걸리는 경우만 로그로 남긴다.
             log.warn("{}: {} EA. {} {}", job, count, TimeUtils.elapsedTimeStr(elapsed.nanoSeconds()), Thread.currentThread().getName());
@@ -108,7 +139,11 @@ public class TsiCvimDbmsWorker extends AbstractTsiCvimWorker implements Runnable
     }
 
     public void report() {
-        long avgTime = 0;
-        log.info("Packet: Remain Q: {}, Average: {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(avgTime), Thread.currentThread().getName());
+        log.info("DbmsWorker({}), Queue Total/Size/Remain: {}/{}/{}, Average: {}, {}",
+                this.idx,
+                this.qSize, this.DATA_QUEUE.size(), this.DATA_QUEUE.remainingCapacity(),
+                TimeUtils.elapsedTimeStr(this.avgTime),
+                Thread.currentThread().getName());
     }
+
 }

+ 51 - 19
src/main/java/com/tsi/comm/server/process/logging/TsiCvimLoggingProcess.java

@@ -7,46 +7,68 @@ import com.tsi.comm.server.process.AbstractTsiCvimWorker;
 import com.tsi.comm.server.protocol.AbstractTsiPacket;
 import com.tsi.comm.server.repository.TsiNodeManager;
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
 @Getter
+@RequiredArgsConstructor
 @Service
 public class TsiCvimLoggingProcess extends AbstractTsiCvimProcess {
 
-    private List<TsiCvimLoggingWorker> workerList = new ArrayList<TsiCvimLoggingWorker>();
+//    private List<TsiCvimLoggingWorker> workerList = new ArrayList<TsiCvimLoggingWorker>();
+    private final TsiNodeManager nodeManager;
+    private ExecutorService executor = null;
 
-    @PostConstruct
-    void init() {
+    public void start() {
         ThreadGroup workerGroup = new ThreadGroup("loggingProcess");
         TsiCvimServerConfig tsiCvimServerConfig = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
 
         this.workers = tsiCvimServerConfig.getLoggingWorkers();
         if (this.workers <= 0) this.workers = 1;
-        int nodes = TsiNodeManager.getInstance().size();
-        int qSize = tsiCvimServerConfig.getQueueSize();
+        int nodes = this.nodeManager.size();
+        int qSize = nodes;
         if (nodes > qSize) {
             qSize = nodes;
         }
-        qSize *= 6;
-        qSize /= this.workers;
+        if (this.workers == 1) {
+            qSize *= 2;
+        }
+
+        this.executor = Executors.newFixedThreadPool(this.workers, new ThreadFactory() {
+            private int count = 0;
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(workerGroup, r);
+                t.setName(String.format("logWorker-%02d.%02d", workers, ++count));
+                t.setDaemon(true);
+                return t;
+            }
+        });
+
         for (int ii = 0; ii < this.workers; ii++) {
             TsiCvimLoggingWorker loggingWorker = new TsiCvimLoggingWorker(ii, qSize);
             this.workerList.add(loggingWorker);
-            Thread worker = new Thread(workerGroup, loggingWorker);
-            worker.setName(String.format("logWorker-%02d.%02d", this.workers, ii+1));
-            worker.setDaemon(true);
-            this.threadList.add(worker);
-        }
-        for (Thread worker : this.threadList) {
-            worker.start();
+            this.executor.submit(loggingWorker); // 여기서 실행됨!
         }
+
+//        for (int ii = 0; ii < this.workers; ii++) {
+//            TsiCvimLoggingWorker loggingWorker = new TsiCvimLoggingWorker(ii, qSize);
+//            this.workerList.add(loggingWorker);
+//            Thread worker = new Thread(workerGroup, loggingWorker);
+//            worker.setName(String.format("logWorker-%02d.%02d", this.workers, ii+1));
+//            worker.setDaemon(true);
+//            this.threadList.add(worker);
+//        }
+//        for (Thread worker : this.threadList) {
+//            worker.start();
+//        }
     }
 
     public boolean add(Object object, int idx) {
@@ -59,14 +81,24 @@ public class TsiCvimLoggingProcess extends AbstractTsiCvimProcess {
         }
         catch (Exception e) {
             MDC.put("id", Long.toString(packet.getNodeId()));
-            log.error("QUEUE_DATA.add: Exception: {}, {}", packet.getNodeId(), e.getMessage());
+            log.error("LoggingProcess: QUEUE_DATA.add: Exception: {}, {}", packet.getNodeId(), e.getMessage());
             MDC.clear();
         }
         return offer;
     }
 
     public void stop() {
-
+        log.info("LoggingProcess Stopping...");
+        this.executor.shutdown();
+        try {
+            if (!this.executor.awaitTermination(3, TimeUnit.SECONDS)) {
+                this.executor.shutdownNow(); // 실행 중인 작업도 중단 시도
+            }
+        } catch (InterruptedException e) {
+            this.executor.shutdownNow();
+            Thread.currentThread().interrupt(); // 현재 스레드도 중단
+        }
+        log.info("LoggingProcess Stopped...");
     }
 
     public void report() {

+ 93 - 63
src/main/java/com/tsi/comm/server/process/logging/TsiCvimLoggingWorker.java

@@ -1,54 +1,81 @@
 package com.tsi.comm.server.process.logging;
 
-import com.tsi.app.common.app.AppUtils;
 import com.tsi.app.common.utils.TimeUtils;
-import com.tsi.comm.server.mongo.dto.TcsNodeStatus;
-import com.tsi.comm.server.mongo.repository.TsiNodeStatusRepository;
 import com.tsi.comm.server.process.AbstractTsiCvimWorker;
 import com.tsi.comm.server.protocol.AbstractTsiPacket;
-import com.tsi.comm.server.protocol.TsiCpuPacket;
+import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
+@Getter
 public class TsiCvimLoggingWorker extends AbstractTsiCvimWorker implements Runnable {
 
     private final LinkedBlockingQueue<AbstractTsiPacket> DATA_QUEUE;
-    private TsiNodeStatusRepository tsiNodeStatusRepository;
+//    private TsiNodeStatusRepository tsiNodeStatusRepository;
+    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
     public TsiCvimLoggingWorker(int idx, int qSize) {
         this.idx = idx;
         this.qSize = qSize;
         this.DATA_QUEUE = new LinkedBlockingQueue<>(qSize);
-        try {
-            this.tsiNodeStatusRepository = (TsiNodeStatusRepository) AppUtils.getBean(TsiNodeStatusRepository.class);
-        }
-        catch(Exception e) {
-            this.tsiNodeStatusRepository = null;
-            log.error("MongoDB: {}", e.getMessage());
-        }
+//        try {
+//            this.tsiNodeStatusRepository = (TsiNodeStatusRepository) AppUtils.getBean(TsiNodeStatusRepository.class);
+//        }
+//        catch(Exception e) {
+//            this.tsiNodeStatusRepository = null;
+//            log.error("MongoDB: {}", e.getMessage());
+//        }
+        this.sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
     }
 
+
     @Override
     public void run() {
-        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
-        while (true) {
-            try {
-                AbstractTsiPacket packet = this.DATA_QUEUE.take();
-                if (packet != null) {
-                    process(packet);
+        log.info("LoggingWorker({}): {} Start. QSIZE: {}", this.idx, Thread.currentThread().getName(), this.qSize);
+        try {
+            while (!Thread.currentThread().isInterrupted()) {
+                try {
+                    AbstractTsiPacket packet = this.DATA_QUEUE.poll(1, TimeUnit.SECONDS); // 인터럽트 감지 가능
+                    if (packet != null) {
+                        process(packet);
+                    } else {
+                        Thread.yield(); // 대기 중 CPU 양보
+                    }
+                } catch (InterruptedException ie) {
+                    log.warn("LoggingWorker({}): {} Interrupted. Exiting...", this.idx, Thread.currentThread().getName());
+                    Thread.currentThread().interrupt(); // 상태 복구
+                    break;
+                } catch (Exception e) {
+                    log.error("LoggingWorker({}): {} Exception: {}", this.idx, Thread.currentThread().getName(), e.getMessage());
                 }
             }
-            catch (Exception e) {
-                log.error("Exception(LoggingWorker while): {}", e.getMessage());
-            }
+        } finally {
+            log.info("LoggingWorker({}): {} Stopped.", this.idx, Thread.currentThread().getName());
         }
     }
 
+//    @Override
+//    public void run() {
+//        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
+//        while (true) {
+//            try {
+//                AbstractTsiPacket packet = this.DATA_QUEUE.take();
+//                if (packet != null) {
+//                    process(packet);
+//                }
+//            }
+//            catch (Exception e) {
+//                log.error("Exception(LoggingWorker while): {}", e.getMessage());
+//            }
+//        }
+//    }
+
     /*
      *  작업큐에 데이터 추가
      */
@@ -56,18 +83,18 @@ public class TsiCvimLoggingWorker extends AbstractTsiCvimWorker implements Runna
         boolean offer = false;
         AbstractTsiPacket packet = (AbstractTsiPacket)object;
         try {
-            //offer => full -> return
-            //add   => full -> wait
-            offer = this.DATA_QUEUE.offer(packet);
+            offer = this.DATA_QUEUE.offer(packet);  //offer => full -> return, add => full -> wait
             if (!offer) {
                 MDC.put("id", Long.toString(packet.getNodeId()));
-                log.error("Logging Queue.offer: {}/{}, {}, Queue Full: {} EA, {}, {}",
-                        packet.getNodeId(), this.DATA_QUEUE.size(), this.idx, this.qSize, TimeUtils.elapsedTime(packet.getRcv()), Thread.currentThread().getName());
+                log.error("LoggingWorker({}): Queue.offer(Full): {}, {}/{}/{}, {}, {}",
+                        this.idx, packet.getNodeId(),
+                        this.DATA_QUEUE.size(), this.qSize, this.DATA_QUEUE.remainingCapacity(),
+                        TimeUtils.elapsedTime(packet.getRcv()), Thread.currentThread().getName());
                 MDC.clear();
             }
         } catch (Exception e) {
             MDC.put("id", Long.toString(packet.getNodeId()));
-            log.error("Logging Queue.offer: Exception: {}, {}, {}", packet.getNodeId(), Thread.currentThread().getName(), e.getMessage());
+            log.error("LoggingWorker({}): Queue.offer: Exception: {}, {}, {}", this.idx, packet.getNodeId(), Thread.currentThread().getName(), e.getMessage());
             MDC.clear();
         }
         return offer;
@@ -75,35 +102,32 @@ public class TsiCvimLoggingWorker extends AbstractTsiCvimWorker implements Runna
 
     public void process(Object object) {
         AbstractTsiPacket packet = (AbstractTsiPacket)object;
-        long add = packet.getAdd() - packet.getRcv();
-        long pop = packet.getPop() - packet.getAdd();
-        long par = packet.getPar() - packet.getPop();
-        long kaf = packet.getEnd() - packet.getPar();
-        long mongo = 0, jobTotal = 0;
+//        long add = packet.getAdd() - packet.getRcv();
+//        long pop = packet.getPop() - packet.getAdd();
+//        long par = packet.getPar() - packet.getPop();
+//        long kaf = packet.getEnd() - packet.getPar();
+//        long mongo = 0, jobTotal = 0;
         long job = packet.getEnd() - packet.getRcv();
 
-        Date date = new java.util.Date(packet.getTimespec().times() * 1000L);
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
-        String collectTime = sdf.format(date);
+        Date date = new Date(packet.getTimespec().times() * 1000L);
+        String collectTime = this.sdf.format(date);
 
-        if (this.tsiNodeStatusRepository != null && (packet instanceof TsiCpuPacket)) {
-            try {
-                long start = System.nanoTime();
-                TsiCpuPacket cpuPacket = (TsiCpuPacket) packet;
-                TcsNodeStatus mongoStatus = cpuPacket.getNodeStatus();
-                if (mongoStatus != null) {
-                    //log.info("{}", mongoStatus.toString());
-                    this.tsiNodeStatusRepository.save(mongoStatus);
-                    mongo = System.nanoTime() - start;
-                    packet.setEnd(System.nanoTime());
-                    jobTotal = packet.getEnd() - packet.getRcv();
-                }
-            }
-            catch (Exception e) {
-                log.error("Node: {}, MongoDB parsing error.", packet.getNodeId());
-            }
-        }
+//        if (this.tsiNodeStatusRepository != null && (packet instanceof TsiCpuPacket)) {
+//            try {
+//                long start = System.nanoTime();
+//                TsiCpuPacket cpuPacket = (TsiCpuPacket) packet;
+//                TcsNodeStatus mongoStatus = cpuPacket.getNodeStatus();
+//                if (mongoStatus != null) {
+//                    this.tsiNodeStatusRepository.save(mongoStatus);
+//                    mongo = System.nanoTime() - start;
+//                    packet.setEnd(System.nanoTime());
+//                    jobTotal = packet.getEnd() - packet.getRcv();
+//                }
+//            }
+//            catch (Exception e) {
+//                log.error("Node: {}, MongoDB parsing error.", packet.getNodeId());
+//            }
+//        }
 
         MDC.put("id", Long.toString(packet.getNodeId()));
 //        log.info("{} Node: {},      Q-Add: {} {}", collectTime, packet.getNodeId(), TimeUtils.elapsedTimeStr(add), Thread.currentThread().getName());
@@ -117,19 +141,25 @@ public class TsiCvimLoggingWorker extends AbstractTsiCvimWorker implements Runna
                 Thread.currentThread().getName(),
                 packet.getPacketLength(),
                 TimeUtils.elapsedTimeStr(packet.getAvg()));
-        if (mongo > 0) {
-            log.info("{} Node: {},    MongoDb: {} {}", collectTime, packet.getNodeId(), TimeUtils.elapsedTimeStr(mongo), Thread.currentThread().getName());
-            log.info("{} Node: {},  Total Job: {} {}",
-                    collectTime,
-                    packet.getNodeId(),
-                    TimeUtils.elapsedTimeStr(jobTotal),
-                    Thread.currentThread().getName());
-        }
-//        log.info("{} Node: {}, ====", collectTime, packet.getNodeId());
+//        if (mongo > 0) {
+//            log.info("{} Node: {},    MongoDb: {} {}", collectTime, packet.getNodeId(), TimeUtils.elapsedTimeStr(mongo), Thread.currentThread().getName());
+//            log.info("{} Node: {},  Total Job: {} {}",
+//                    collectTime,
+//                    packet.getNodeId(),
+//                    TimeUtils.elapsedTimeStr(jobTotal),
+//                    Thread.currentThread().getName());
+//        }
+
+        //        log.info("{} Node: {}, ====", collectTime, packet.getNodeId());
         MDC.clear();
+        calcProcessTime(packet.getRcv());
     }
 
     public void report() {
-        log.info("Logging: Remain Q: {}, Average {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(this.avgTime), Thread.currentThread().getName());
+        log.info("LoggingWorker({}), Queue Total/Size/Remain: {}/{}/{}, Average: {}, {}",
+                this.idx,
+                this.qSize, this.DATA_QUEUE.size(), this.DATA_QUEUE.remainingCapacity(),
+                TimeUtils.elapsedTimeStr(this.avgTime),
+                Thread.currentThread().getName());
     }
 }

+ 49 - 22
src/main/java/com/tsi/comm/server/process/packet/TsiCvimPacketProcess.java

@@ -8,48 +8,65 @@ import com.tsi.comm.server.process.AbstractTsiCvimWorker;
 import com.tsi.comm.server.protocol.AbstractTsiPacket;
 import com.tsi.comm.server.repository.TsiNodeManager;
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
 @Getter
+@RequiredArgsConstructor
 @Service
 public class TsiCvimPacketProcess extends AbstractTsiCvimProcess {
 
     private final KafkaProducerService kafkaProducerService;
+    private final TsiNodeManager nodeManager;
+    private ExecutorService executor = null;
 
-    public TsiCvimPacketProcess(KafkaProducerService kafkaProducerService) {
-        this.kafkaProducerService = kafkaProducerService;
-    }
-
-    @PostConstruct
-    void init() {
+    public void start() {
         ThreadGroup workerGroup = new ThreadGroup("packetProcess");
         TsiCvimServerConfig tsiCvimServerConfig = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
 
         this.workers = tsiCvimServerConfig.getPacketWorkers();
         if (this.workers <= 0) this.workers = 1;
-        int nodes = TsiNodeManager.getInstance().size();
-        int qSize = tsiCvimServerConfig.getQueueSize();
-        if (nodes > qSize) {
-            qSize = nodes;
+        int nodes = this.nodeManager.size();
+        int qSize = nodes;
+        if (this.workers == 1) {
+            qSize *= 3;
         }
-        qSize *= 4;
-        qSize /= this.workers;
+
+        this.executor = Executors.newFixedThreadPool(this.workers, new ThreadFactory() {
+            private int count = 0;
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(workerGroup, r);
+                t.setName(String.format("logWorker-%02d.%02d", workers, ++count));
+                t.setDaemon(true);
+                return t;
+            }
+        });
+
         for (int ii = 0; ii < this.workers; ii++) {
             TsiCvimPacketWorker packetWorker = new TsiCvimPacketWorker(ii, qSize, this.kafkaProducerService);
             this.workerList.add(packetWorker);
-            Thread worker = new Thread(workerGroup, packetWorker);
-            worker.setName(String.format("pktWorker-%02d.%02d", this.workers, ii+1));
-            worker.setDaemon(true);
-            this.threadList.add(worker);
-        }
-        for (Thread worker : this.threadList) {
-            worker.start();
+            this.executor.submit(packetWorker); // 여기서 실행됨!
         }
+
+//        for (int ii = 0; ii < this.workers; ii++) {
+//            TsiCvimPacketWorker packetWorker = new TsiCvimPacketWorker(ii, qSize, this.kafkaProducerService);
+//            this.workerList.add(packetWorker);
+//            Thread worker = new Thread(workerGroup, packetWorker);
+//            worker.setName(String.format("pktWorker-%02d.%02d", this.workers, ii+1));
+//            worker.setDaemon(true);
+//            this.threadList.add(worker);
+//        }
+//        for (Thread worker : this.threadList) {
+//            worker.start();
+//        }
     }
 
     public boolean add(Object object, int idx) {
@@ -62,14 +79,24 @@ public class TsiCvimPacketProcess extends AbstractTsiCvimProcess {
         }
         catch (Exception e) {
             MDC.put("id", Long.toString(packet.getNodeId()));
-            log.error("QUEUE_DATA.add: Exception: {}, {}", packet.getNodeId(), e.getMessage());
+            log.error("PacketProcess: QUEUE_DATA.add: Exception: {}, {}", packet.getNodeId(), e.getMessage());
             MDC.clear();
         }
         return offer;
     }
 
     public void stop() {
-
+        log.info("PacketProcess Stopping...");
+        this.executor.shutdown();
+        try {
+            if (!this.executor.awaitTermination(3, TimeUnit.SECONDS)) {
+                this.executor.shutdownNow(); // 실행 중인 작업도 중단 시도
+            }
+        } catch (InterruptedException e) {
+            this.executor.shutdownNow();
+            Thread.currentThread().interrupt(); // 현재 스레드도 중단
+        }
+        log.info("PacketProcess Stopped...");
     }
 
     public void report() {

+ 102 - 49
src/main/java/com/tsi/comm/server/process/packet/TsiCvimPacketWorker.java

@@ -11,6 +11,7 @@ import com.tsi.comm.server.protocol.AbstractTsiPacket;
 import com.tsi.comm.server.protocol.TsiCpuDisconnected;
 import com.tsi.comm.server.protocol.TsiCpuPacket;
 import com.tsi.comm.server.vo.TsiNodeVo;
+import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 
@@ -18,6 +19,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 @Slf4j
+@Getter
 public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnable {
 
     //private ConcurrentLinkedQueue<AbstractTsiPacket> DATA_QUEUE;
@@ -30,40 +32,75 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
         this.idx = idx;
         this.qSize = qSize;
         this.kafkaProducer = kafkaProducer;
-        this.loggingService = (TsiCvimLoggingProcess) AppUtils.getBean(TsiCvimLoggingProcess.class);
         this.DATA_QUEUE = new LinkedBlockingQueue<>(qSize);
+        this.loggingService = (TsiCvimLoggingProcess) AppUtils.getBean(TsiCvimLoggingProcess.class);
         this.cvimServerConfig = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);
     }
 
     @Override
     public void run() {
-        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
-        while (true) {
-            Object packet = null;
-            try {
-                packet = this.DATA_QUEUE.take();
-                if (packet != null) {
-                    process(packet);
-                }
-                else {
-                    Thread.yield();
-                }
-            }
-            catch (Exception e) {
-                if (packet != null) {
-                    TsiCpuPacket cpuPacket = (TsiCpuPacket)((AbstractTsiPacket)packet);
-                    TsiNodeVo nodeVo = (TsiNodeVo)cpuPacket.getObj();
-                    if (nodeVo != null) {
-                        log.warn(" Node: {}, Network Conn: {}", nodeVo.getKey(), nodeVo.isConnect());
+        log.info("PacketWorker({}): {} Start. QSIZE: {}", this.idx, Thread.currentThread().getName(), this.qSize);
+        try {
+            while (!Thread.currentThread().isInterrupted()) {
+                Object packet = null;
+                try {
+                    packet = this.DATA_QUEUE.poll(1, TimeUnit.SECONDS); // 인터럽트 감지 가능
+                    if (packet != null) {
+                        process(packet);
+                    } else {
+                        Thread.yield(); // 대기 중 CPU 양보
+                    }
+                } catch (InterruptedException ie) {
+                    log.warn("PacketWorker({}): {} Interrupted. Exiting...", this.idx, Thread.currentThread().getName());
+                    Thread.currentThread().interrupt(); // 상태 복구
+                    break;
+                } catch (Exception e) {
+                    if (packet != null) {
+                        TsiCpuPacket cpuPacket = (TsiCpuPacket)((AbstractTsiPacket)packet);
+                        TsiNodeVo nodeVo = (TsiNodeVo)cpuPacket.getObj();
+                        if (nodeVo != null) {
+                            log.warn("PacketWorker({}): {} Node: {}, Network Conn: {}", this.idx, Thread.currentThread().getName(), nodeVo.getKey(), nodeVo.isConnect());
+                        }
+                    }
+                    else {
+                        log.error("PacketWorker({}): {} Exception: {}", this.idx, Thread.currentThread().getName(), e.getMessage());
                     }
-                }
-                else {
-                    log.error("Exception(PacketWorker while): {}", e.getMessage());
                 }
             }
+        } finally {
+            log.info("PacketWorker({}): {} Stopped.", this.idx, Thread.currentThread().getName());
         }
     }
 
+//    @Override
+//    public void run() {
+//        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
+//        while (true) {
+//            Object packet = null;
+//            try {
+//                packet = this.DATA_QUEUE.take();
+//                if (packet != null) {
+//                    process(packet);
+//                }
+//                else {
+//                    Thread.yield();
+//                }
+//            }
+//            catch (Exception e) {
+//                if (packet != null) {
+//                    TsiCpuPacket cpuPacket = (TsiCpuPacket)((AbstractTsiPacket)packet);
+//                    TsiNodeVo nodeVo = (TsiNodeVo)cpuPacket.getObj();
+//                    if (nodeVo != null) {
+//                        log.warn(" Node: {}, Network Conn: {}", nodeVo.getKey(), nodeVo.isConnect());
+//                    }
+//                }
+//                else {
+//                    log.error("Exception(PacketWorker while): {}", e.getMessage());
+//                }
+//            }
+//        }
+//    }
+
     /*
      *  작업큐에 데이터 추가
      */
@@ -71,18 +108,18 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
         boolean offer = false;
         AbstractTsiPacket packet = (AbstractTsiPacket)object;
         try {
-            //offer => full -> return
-            //add   => full -> wait
-            offer = this.DATA_QUEUE.offer(packet);
+            offer = this.DATA_QUEUE.offer(packet);  //offer => full -> return, add => full -> wait
             if (!offer) {
                 MDC.put("id", Long.toString(packet.getNodeId()));
-                log.error("Packet Queue.offer: {}/{}, {}, Queue Full: {} EA, {}, {}",
-                        packet.getNodeId(), this.DATA_QUEUE.size(), this.idx, this.qSize, TimeUtils.elapsedTime(packet.getRcv()), Thread.currentThread().getName());
+                log.error("PacketWorker({}): Queue.offer(Full): {}, {}/{}/{}, {}, {}",
+                        this.idx, packet.getNodeId(),
+                        this.DATA_QUEUE.size(), this.qSize, this.DATA_QUEUE.remainingCapacity(),
+                        TimeUtils.elapsedTime(packet.getRcv()), Thread.currentThread().getName());
                 MDC.clear();
             }
         } catch (Exception e) {
             MDC.put("id", Long.toString(packet.getNodeId()));
-            log.error("Packet Queue.offer: Exception: {}, {}, {}", packet.getNodeId(), Thread.currentThread().getName(), e.getMessage());
+            log.error("PacketWorker({}): Queue.offer: Exception: {}, {}, {}", this.idx, packet.getNodeId(), Thread.currentThread().getName(), e.getMessage());
             MDC.clear();
         }
         return offer;
@@ -92,9 +129,10 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
         AbstractTsiPacket packet = (AbstractTsiPacket)object;
         TsiCpuPacket cpuPacket = (TsiCpuPacket)packet;
         TsiNodeVo nodeVo = (TsiNodeVo)cpuPacket.getObj();//TsiNodeManager.getInstance().get(packet.getNodeId());
+        long nodeId = packet.getNodeId();
         if (nodeVo == null) {
             // 노드 정보가 없는 경우
-            log.error("Packet process NodeVo is null: {}, {}", packet.getNodeId(), Thread.currentThread().getName());
+            log.error("Packet process NodeVo is null: {}, {}", nodeId, Thread.currentThread().getName());
             return;
         }
 
@@ -102,25 +140,31 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
 
         long curr = System.nanoTime();
         if (TimeUnit.MILLISECONDS.convert(curr - packet.getRcv(), TimeUnit.NANOSECONDS) > 3000) {
-            log.error("Packet skip::: {}, {} ms.", packet.getNodeId(), TimeUnit.MILLISECONDS.convert(curr - packet.getRcv(), TimeUnit.NANOSECONDS));
+            log.error("Packet skip::: {}, {} ms.", nodeId, TimeUnit.MILLISECONDS.convert(curr - packet.getRcv(), TimeUnit.NANOSECONDS));
             return;
         }
         packet.setPop(curr);
 
         if (packet.getOpCode() == (byte) eOpCode.TSI_CPU_DISCONNECTED.getValue()) {
-            TsiCpuDisconnected disconnected = (TsiCpuDisconnected)packet;
-            disconnected.parsing(nodeVo);
-            if (nodeVo.isSendCvim() && disconnected.getCvimData() != null) {
-                this.kafkaProducer.sendCvim(disconnected.getNodeId(), disconnected.getCvimData());
-            }
+            MDC.put("id", nodeVo.getKey());
+            try {
+                TsiCpuDisconnected disconnected = (TsiCpuDisconnected) packet;
+                disconnected.parsing(nodeVo);
+                if (nodeVo.isSendCvim() && disconnected.getCvimData() != null) {
+                    this.kafkaProducer.sendCvim(disconnected.getNodeId(), disconnected.getCvimData());
+                }
 
-            if (disconnected.getAddNodes() != null) {
-                // 연등지 인 경우
-                for (int ii = 0; ii < disconnected.getAddNodes().size(); ii++) {
-                    this.kafkaProducer.sendCvim(disconnected.getAddNodes().get(ii).getNodeId(), disconnected.getAddNodes().get(ii).getCvimData());
+                if (disconnected.getAddNodes() != null) {
+                    // 연등지 인 경우
+                    for (int ii = 0; ii < disconnected.getAddNodes().size(); ii++) {
+                        this.kafkaProducer.sendCvim(disconnected.getAddNodes().get(ii).getNodeId(), disconnected.getAddNodes().get(ii).getCvimData());
+                    }
                 }
+                this.loggingService.add(packet, loggingIdx);//(int)Thread.currentThread().getId());
+            } catch (Exception e) {
+                log.error("Disconnect Packet parsing error: {}, {}, {}", nodeId, Thread.currentThread().getName(), e.getMessage());
             }
-            this.loggingService.add(packet, loggingIdx);//(int)Thread.currentThread().getId());
+            MDC.clear();
             return;
         }
 
@@ -128,10 +172,15 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
         // 20250425: packet parsing 의 로그를 노드별 로그파일에 저장되도록 MDC 위치 변경
         // 20250425: parsing 함수에 packet-check 여부를 같이 넘겨줘서 CRC 체크여부 확인
         MDC.put("id", nodeVo.getKey());
-        if (!cpuPacket.parsing(nodeVo, this.cvimServerConfig.isCheckPacket())) {
-            // MDC.put("id", nodeVo.getKey());
-            log.error("Packet parsing failed: {}", packet.getNodeId());
-            // MDC.clear();
+        try {
+            if (!cpuPacket.parsing(nodeVo, this.cvimServerConfig.isCheckPacket())) {
+                // MDC.put("id", nodeVo.getKey());
+                log.error("Packet parsing failed: {}", nodeId);
+                // MDC.clear();
+            }
+        }
+        catch (Exception e) {
+            log.error("Cpu Packet parsing error: {}, {}, {}", nodeId, Thread.currentThread().getName(), e.getMessage());
         }
         MDC.clear();
 
@@ -139,13 +188,13 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
 
         // 카프카 전송
         if (nodeVo.isSendNode() && packet.getNodeData() != null) {
-            this.kafkaProducer.sendNode(Long.toString(packet.getNodeId()), packet.getNodeData());
+            this.kafkaProducer.sendNode(Long.toString(nodeId), packet.getNodeData());
         }
         if (nodeVo.isSendTest()) {
-            this.kafkaProducer.sendTest(packet.getNodeId(), packet.getTestData());
+            this.kafkaProducer.sendTest(nodeId, packet.getTestData());
         }
         if (nodeVo.isSendCvim() && packet.getCvimData() != null) {
-            this.kafkaProducer.sendCvim(packet.getNodeId(), packet.getCvimData());
+            this.kafkaProducer.sendCvim(nodeId, packet.getCvimData());
         }
 
         if (cpuPacket.getAddNodes() != null) {
@@ -182,7 +231,11 @@ public class TsiCvimPacketWorker extends AbstractTsiCvimWorker implements Runnab
     }
 
     public void report() {
-        long avgTime = 0;
-        log.info("Packet: Remain Q: {}, Average: {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(avgTime), Thread.currentThread().getName());
+        log.info("PacketWorker({}), Queue Total/Size/Remain: {}/{}/{}, Average: {}, {}",
+                this.idx,
+                this.qSize, this.DATA_QUEUE.size(), this.DATA_QUEUE.remainingCapacity(),
+                TimeUtils.elapsedTimeStr(this.avgTime),
+                Thread.currentThread().getName());
     }
+
 }

+ 5 - 2
src/main/java/com/tsi/comm/server/protocol/TsiCpuDisconnected.java

@@ -1,5 +1,6 @@
 package com.tsi.comm.server.protocol;
 
+import com.tsi.app.common.app.AppUtils;
 import com.tsi.app.common.cpu.enums.eOpCode;
 import com.tsi.app.common.utils.ByteUtils;
 import com.tsi.app.common.utils.TimeUtils;
@@ -16,12 +17,14 @@ import lombok.Setter;
 @Setter
 public class TsiCpuDisconnected extends TsiCpuPacket {
 
+    private final TsiNodeAddManager nodeAddManager;
     public TsiCpuDisconnected(long nodeId, Channel channel) {
         this(nodeId, TimeUtils.currentTimeSeconds(), System.nanoTime(), channel);
     }
     public TsiCpuDisconnected(long nodeId, long msec, long nsec, Channel channel) {
         super(nodeId, msec, nsec, NettyUtils.getRemoteIpAddressToLong(channel), NettyUtils.getRemotePort(channel));
         setOpCode(eOpCode.TSI_CPU_DISCONNECTED.getValue());
+        this.nodeAddManager = (TsiNodeAddManager) AppUtils.getBean(TsiNodeAddManager.class);
     }
 
     protected void makeAddNodeCvimPaket(TsiCpuPacket cpuPacket) {
@@ -38,12 +41,13 @@ public class TsiCpuDisconnected extends TsiCpuPacket {
 
     public boolean parsing(TsiNodeVo obj) {
 
-        TsiNodeAddVo tsiNodeAddVo = TsiNodeAddManager.getInstance().get(this.nodeId);
+        TsiNodeAddVo tsiNodeAddVo = this.nodeAddManager.get(this.nodeId);
         if (tsiNodeAddVo == null) {
             // 연등지 정보가 없는 경우
             makeCvimPacket();
             return true;
         }
+
         // 연등지 노드 카프카 패킷 생성
         for (Integer key : tsiNodeAddVo.getAddNodeMap().keySet()){
             TsiNodeAddDetailVo detailVo = tsiNodeAddVo.getAddNodeMap().get(key);
@@ -51,7 +55,6 @@ public class TsiCpuDisconnected extends TsiCpuPacket {
             makeAddNodeCvimPaket(addPacket);
             this.addNodes.add(addPacket);
         }
-
         return true;
     }
 

+ 6 - 2
src/main/java/com/tsi/comm/server/protocol/TsiCpuPacket.java

@@ -1,5 +1,6 @@
 package com.tsi.comm.server.protocol;
 
+import com.tsi.app.common.app.AppUtils;
 import com.tsi.app.common.cpu.dto.TsiCvimAbnormal;
 import com.tsi.app.common.cpu.dto.TsiCvimControl;
 import com.tsi.app.common.cpu.dto.TsiCvimStatus;
@@ -159,13 +160,16 @@ public class TsiCpuPacket extends AbstractTsiPacket {
 
     protected List<TsiCpuAddPacket> addNodes;
 
+    private final TsiNodeAddManager nodeAddManager;
     public TsiCpuPacket(long nodeId, long msec, long nsec, Channel channel) {
         super(nodeId, msec, nsec, NettyUtils.getRemoteIpAddressToLong(channel), NettyUtils.getRemotePort(channel));
         setOpCode(eOpCode.TSI_CPU_SIGNAL_NOTIFY.getValue());
+        this.nodeAddManager = (TsiNodeAddManager) AppUtils.getBean(TsiNodeAddManager.class);
     }
 
     public TsiCpuPacket(long nodeId, long msec, long nsec, long remoteIpAddressToLong, int remotePort) {
         super(nodeId, msec, nsec, remoteIpAddressToLong, remotePort);
+        this.nodeAddManager = (TsiNodeAddManager) AppUtils.getBean(TsiNodeAddManager.class);
     }
 
     // FOR CVIM packet
@@ -307,7 +311,7 @@ public class TsiCpuPacket extends AbstractTsiPacket {
             }
         }
 
-        TsiNodeAddVo tsiNodeAddVo = TsiNodeAddManager.getInstance().get(this.nodeId);
+        TsiNodeAddVo tsiNodeAddVo = this.nodeAddManager.get(this.nodeId);
         if (tsiNodeAddVo == null) {
             // 연등지 정보가 없는 경우
             // R25 인 경우 마지막 CPU 제조사 코드를 복사하지 않도록 수정
@@ -399,7 +403,7 @@ public class TsiCpuPacket extends AbstractTsiPacket {
 
             TsiCpuAddPacket addPacket = new TsiCpuAddPacket(entry.getKey(), this.timespec, this.remoteIp, this.remotePort);
 
-            addPacket.setObj(TsiNodeAddManager.getInstance().get(entry.getKey()));
+            addPacket.setObj(this.nodeAddManager.get(entry.getKey()));
 
             addPacket.setNodeData(new byte[SIZE_NODE_HEAD + (statusCount*SIZE_STATUS_DATA)]);
             System.arraycopy(head, 0, addPacket.getNodeData(), 0, SIZE_NODE_HEAD);

+ 10 - 0
src/main/java/com/tsi/comm/server/repository/ApplicationRepository.java

@@ -0,0 +1,10 @@
+package com.tsi.comm.server.repository;
+
+import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.comm.server.mybatis.vo.ProcessStateVo;
+
+public class ApplicationRepository {
+
+    public static final ProcessStateVo processStateVo = new ProcessStateVo(AbstractDbmsVo.DBMS_PROCESS_STATE);
+
+}

+ 56 - 33
src/main/java/com/tsi/comm/server/repository/TsiAlarmManager.java

@@ -1,38 +1,26 @@
 package com.tsi.comm.server.repository;
 
-import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
-import com.tsi.comm.server.mybatis.vo.ProcessStateVo;
+import com.tsi.app.common.utils.HexString;
+import com.tsi.app.common.xnet.NettyUtils;
 import com.tsi.comm.server.vo.TsiAlarmConfigVo;
+import io.netty.channel.Channel;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
 
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Slf4j
+@RequiredArgsConstructor
+@Component
 public class TsiAlarmManager {
 
-    private static TsiAlarmManager _instance = null;
+    private final ConcurrentHashMap<String, TsiAlarmConfigVo> tsiAlarmConfigMap = new ConcurrentHashMap<>();
+    private final Set<String> UNKNOWN_NODE_SET = ConcurrentHashMap.newKeySet();
+    private final Set<String> UNKNOWN_NODE_BUF_SET = ConcurrentHashMap.newKeySet();
 
-    public static TsiAlarmManager getInstance() {
-        if (_instance == null) {
-            synchronized (TsiAlarmManager.class) {
-                if (_instance == null)
-                    _instance = new TsiAlarmManager();
-            }
-        }
-        return _instance;
-    }
-
-    private ConcurrentHashMap<String, TsiAlarmConfigVo> tsiAlarmConfigMap;
-    private ProcessStateVo processStateVo;
-
-    private TsiAlarmManager() {
-        this.tsiAlarmConfigMap = new ConcurrentHashMap<>();
-        this.processStateVo = new ProcessStateVo(AbstractDbmsVo.DBMS_PROCESS_STATE);
-    }
-
-    public ProcessStateVo getProcessStateVo() {
-        return this.processStateVo;
-    }
     public TsiAlarmConfigVo get(String code) {
         return this.tsiAlarmConfigMap.get(code);
     }
@@ -44,20 +32,55 @@ public class TsiAlarmManager {
         return this.tsiAlarmConfigMap.size();
     }
 
-    public boolean containsKey(String key) {
-        return this.tsiAlarmConfigMap.containsKey(key);
-    }
-
     public boolean checkAlarm(String code) {
         TsiAlarmConfigVo vo = get(code);
         return (vo != null && vo.isUseYn());
     }
-    public boolean isAlarm(String code, int value) {
-        TsiAlarmConfigVo vo = get(code);
-        if (vo != null && vo.isUseYn()) {
-            return (value > vo.getValue());
+
+//    public boolean containsKey(String key) {
+//        return this.tsiAlarmConfigMap.containsKey(key);
+//    }
+
+//    public boolean isAlarm(String code, int value) {
+//        TsiAlarmConfigVo vo = get(code);
+//        if (vo != null && vo.isUseYn()) {
+//            return (value > vo.getValue());
+//        }
+//        return false;
+//    }
+
+    public void loggingUnknownNode(long nodeId, Channel channel) {
+        final String remoteIpAddress = NettyUtils.getRemoteIpAddress(channel);
+        if (this.UNKNOWN_NODE_SET.contains(remoteIpAddress)) {
+            return; // 이미 등록된 IP 주소는 무시
         }
-        return false;
+        this.UNKNOWN_NODE_SET.add(remoteIpAddress);
+
+        final String fileName = "unknown_node";
+        MDC.put("report", fileName);
+        log.info("The node ID of the first received packet is not registered: {}, {}", nodeId, remoteIpAddress);
+        MDC.remove(fileName);
+        MDC.clear();
+    }
+    public void loggingUnknownNodePacket(long nodeId, Channel channel, byte[] buf) {
+        final String remoteIpAddress = NettyUtils.getRemoteIpAddress(channel);
+        if (this.UNKNOWN_NODE_BUF_SET.contains(remoteIpAddress)) {
+            return; // 이미 등록된 IP 주소는 무시
+        }
+        this.UNKNOWN_NODE_BUF_SET.add(remoteIpAddress);
+
+        final String fileName = "unknown_node";
+        MDC.put("report", fileName);
+        log.info("Node: {}, {}, [{}]", nodeId, remoteIpAddress, HexString.fromBytes(buf));
+        MDC.remove(fileName);
+        MDC.clear();
+    }
+    public void loggingAddUnknownNode(long nodeId, Channel channel) {
+        final String fileName = "unknown_node";
+        MDC.put("report", fileName);
+        log.info("Unknown node id registered: {}, {}", nodeId, channel);
+        MDC.remove(fileName);
+        MDC.clear();
     }
 
 }

+ 7 - 17
src/main/java/com/tsi/comm/server/repository/TsiNodeAddManager.java

@@ -1,28 +1,18 @@
 package com.tsi.comm.server.repository;
 
 import com.tsi.comm.server.vo.TsiNodeAddVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
 
 import java.util.concurrent.ConcurrentHashMap;
 
+@Slf4j
+@RequiredArgsConstructor
+@Component
 public class TsiNodeAddManager {
 
-    private static TsiNodeAddManager _instance = null;
-
-    public static TsiNodeAddManager getInstance() {
-        if (_instance == null) {
-            synchronized (TsiNodeAddManager.class) {
-                if (_instance == null)
-                    _instance = new TsiNodeAddManager();
-            }
-        }
-        return _instance;
-    }
-
-    private TsiNodeAddManager() {
-        this.tsiNodeAddMap = new ConcurrentHashMap<>();
-    }
-
-    private ConcurrentHashMap<Long, TsiNodeAddVo> tsiNodeAddMap;
+    private final ConcurrentHashMap<Long, TsiNodeAddVo> tsiNodeAddMap = new ConcurrentHashMap<>();
 
     public TsiNodeAddVo get(long nodeId) {
         return this.tsiNodeAddMap.get(nodeId);

+ 7 - 148
src/main/java/com/tsi/comm/server/repository/TsiNodeManager.java

@@ -1,42 +1,21 @@
 package com.tsi.comm.server.repository;
 
-import com.tsi.app.common.app.AppUtils;
-import com.tsi.app.common.xnet.NettyUtils;
-import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
-import com.tsi.comm.server.mybatis.vo.AlarmOccrVo;
-import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
-import com.tsi.comm.server.vo.TsiAlarmConfigVo;
 import com.tsi.comm.server.vo.TsiNodeVo;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
 
-import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Slf4j
+@Getter
+@RequiredArgsConstructor
+@Component
 public class TsiNodeManager {
 
-    private static TsiNodeManager _instance = null;
-
-    public static TsiNodeManager getInstance() {
-        if (_instance == null) {
-            synchronized (TsiNodeManager.class) {
-                if (_instance == null)
-                    _instance = new TsiNodeManager();
-            }
-        }
-        return _instance;
-    }
-
-    private TsiNodeManager() {
-        this.tsiNodeVoMap = new ConcurrentHashMap<>();
-        this.dbmsProcess = (TsiCvimDbmsProcess) AppUtils.getBean(TsiCvimDbmsProcess.class);
-    }
-
-    private ConcurrentHashMap<Long, TsiNodeVo> tsiNodeVoMap;
-    // DB Process Service
-    private TsiCvimDbmsProcess dbmsProcess;
+    private final ConcurrentHashMap<Long, TsiNodeVo> tsiNodeVoMap = new ConcurrentHashMap<>();
 
     public TsiNodeVo get(long nodeId) {
         return this.tsiNodeVoMap.get(nodeId);
@@ -74,124 +53,4 @@ public class TsiNodeManager {
         }
     }
 
-    public void reportNodeSessions() {
-        log.info("================================================================================================================");
-        log.info("Report Node Sessions: {} Nodes.", this.tsiNodeVoMap.size());
-
-        int registered = 0;
-        int unknown = 0;
-        int connected = 0;
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
-
-        log.info("{}", String.format("%10s %4s %7s %19s %19s %9s %6s %19s  Remote-Address", "ID", "UNTC", "Connect", "Connect Time", "Disconnect Time", "Connected", "Closed", "Last-Recv-Time"));
-        log.info("----------------------------------------------------------------------------------------------------------------");
-
-//        this.tsiNodeVoMap.entrySet().stream()
-//                .sorted(Map.Entry.comparingByKey()) // 키값 기준 오름차순 정렬
-//                .forEach(entry -> {
-//                    TsiNodeVo node = entry.getValue();
-//                    String check = (node.isInstalled() ? "Y" : "N")
-//                            + (node.isSendNode() ? "Y" : "N")
-//                            + (node.isSendTest() ? "Y" : "N")
-//                            + (node.isSendCvim() ? "Y" : "N");
-//
-//                    if (node.isRegistered()) {
-//                        registered.getAndIncrement();
-//                    } else {
-//                        unknown++;
-//                    }
-//
-//                    String connect;
-//                    String info;
-//                    if (node.isConnect()) {
-//                        connected++;
-//                        connect = "Y";
-//                        info = NettyUtils.getRemoteAddress(node.getChannel());
-//                    } else {
-//                        connect = "N";
-//                        info = "---";
-//                    }
-//
-//                    String connectTm = sdf.format(new Date(node.getConnectTm()));
-//                    String disconnectTm = sdf.format(new Date(node.getDisconnectTm()));
-//                    String lastCommTm = sdf.format(new Date(node.getLastCommTm()));
-//
-//                    log.info("{}", String.format(
-//                            "%10s %4s %7s %19s %19s %9d %6d %19s  %s",
-//                            node.getKey(), check, connect, connectTm,
-//                            disconnectTm, node.getConnectCount().get(),
-//                            node.getDisconnectCount().get(), lastCommTm, info
-//                    ));
-//                });
-//
-         for (Map.Entry<Long, TsiNodeVo> obj : this.tsiNodeVoMap.entrySet()) {
-             TsiNodeVo node = obj.getValue();
-             String check = (node.isInstalled() ? "Y" : "N");
-             check = check + (node.isSendNode() ? "Y" : "N");
-             check = check + (node.isSendTest() ? "Y" : "N");
-             check = check + (node.isSendCvim() ? "Y" : "N");
-             if (node.isRegistered()) {
-                 registered++;
-             }
-             else {
-                 unknown++;
-             }
-
-             String connect;
-             String info;
-             if (node.isConnect()) {
-                 connected++;
-                 connect = "Y";
-                 info = NettyUtils.getRemoteAddress(node.getChannel());
-             }
-             else {
-                 connect = "N";
-                 info = "---";
-             }
-
-             String connectTm = sdf.format(new Date(node.getConnectTm()));
-             String disconnectTm = sdf.format(new Date(node.getDisconnectTm()));
-             String lastCommTm = sdf.format(new Date(node.getLastCommTm()));
-
-             log.info("{}", String.format("%10s %4s %7s %19s %19s %9d %6d %19s  %s", node.getKey(), check, connect, connectTm, disconnectTm, node.getConnectCount().get(), node.getDisconnectCount().get(), lastCommTm, info));
-        }
-        log.info("----------------------------------------------------------------------------------------------------------------");
-        log.info("Total Nodes: {} EA, Registered: {} EA, Unknown: {} EA, Connected: {} EA", this.tsiNodeVoMap.size(), registered, unknown, connected);
-        log.info("==============================================");
-    }
-
-    public void checkSessionTimeout(long timeout) {
-
-        String connectTm;
-        String lastCommTm;
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
-        long currTm = System.currentTimeMillis();
-        for (Map.Entry<Long, TsiNodeVo> obj : this.tsiNodeVoMap.entrySet()) {
-            TsiNodeVo node = obj.getValue();
-            if (node.isConnect()) {
-                if ((currTm - node.getLastCommTm()) > timeout) {
-                    try {
-                        AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
-                        alarm.setAlarmCode(TsiAlarmConfigVo.COMM_02);
-                        alarm.setAlarmTarget(node.getKey());
-                        alarm.setAlarmValue(NettyUtils.getRemoteIpAddress(node.getChannel()));
-//                        this.dbmsProcess.add(alarm, (int) Thread.currentThread().getId());
-
-                        connectTm = sdf.format(new Date(node.getConnectTm()));
-                        lastCommTm = sdf.format(new Date(node.getLastCommTm()));
-                        log.warn("Node: {}, Recv Timeout: Connect: {}, LastCommTime: {}, timeout: {}",
-                                node.getKey(), connectTm, lastCommTm, timeout);
-
-//                        node.getChannel().disconnect();
-//                        node.getChannel().close();
-                    }
-                    catch (Exception e) {
-                        log.error("checkSessionTimeout: {}", e.getMessage());
-                    }
-                }
-            }
-        }
-    }
 }

+ 221 - 0
src/main/java/com/tsi/comm/server/repository/TsiReportManager.java

@@ -0,0 +1,221 @@
+package com.tsi.comm.server.repository;
+
+import com.tsi.app.common.utils.TimeUtils;
+import com.tsi.app.common.xnet.NettyUtils;
+import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.comm.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.comm.server.process.AbstractTsiCvimWorker;
+import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
+import com.tsi.comm.server.process.dbms.TsiCvimDbmsWorker;
+import com.tsi.comm.server.process.logging.TsiCvimLoggingProcess;
+import com.tsi.comm.server.process.logging.TsiCvimLoggingWorker;
+import com.tsi.comm.server.process.packet.TsiCvimPacketProcess;
+import com.tsi.comm.server.process.packet.TsiCvimPacketWorker;
+import com.tsi.comm.server.vo.TsiAlarmConfigVo;
+import com.tsi.comm.server.vo.TsiNodeVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class TsiReportManager {
+
+    private final TsiNodeManager nodeManager;
+    private final TsiCvimDbmsProcess dbmsProcess;
+    private final TsiCvimLoggingProcess loggingProcess;
+    private final TsiCvimPacketProcess packetProcess;
+
+    public void reportNodeSessions() {
+        final String fileName = "report";
+        MDC.put("report", fileName);
+
+        int nodeCount = this.nodeManager.getTsiNodeVoMap().size();
+        log.info("================================================================================================================");
+        log.info("Report Node Sessions: {} Nodes.", nodeCount);
+
+        int registered = 0;
+        int unknown = 0;
+        int connected = 0;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+
+        log.info("{}", String.format("%10s %4s %7s %19s %19s %9s %6s %19s  Remote-Address", "ID", "UNTC", "Connect", "Connect Time", "Disconnect Time", "Connected", "Closed", "Last-Recv-Time"));
+        log.info("----------------------------------------------------------------------------------------------------------------");
+
+//        this.tsiNodeVoMap.entrySet().stream()
+//                .sorted(Map.Entry.comparingByKey()) // 키값 기준 오름차순 정렬
+//                .forEach(entry -> {
+//                    TsiNodeVo node = entry.getValue();
+//                    String check = (node.isInstalled() ? "Y" : "N")
+//                            + (node.isSendNode() ? "Y" : "N")
+//                            + (node.isSendTest() ? "Y" : "N")
+//                            + (node.isSendCvim() ? "Y" : "N");
+//
+//                    if (node.isRegistered()) {
+//                        registered.getAndIncrement();
+//                    } else {
+//                        unknown++;
+//                    }
+//
+//                    String connect;
+//                    String info;
+//                    if (node.isConnect()) {
+//                        connected++;
+//                        connect = "Y";
+//                        info = NettyUtils.getRemoteAddress(node.getChannel());
+//                    } else {
+//                        connect = "N";
+//                        info = "---";
+//                    }
+//
+//                    String connectTm = sdf.format(new Date(node.getConnectTm()));
+//                    String disconnectTm = sdf.format(new Date(node.getDisconnectTm()));
+//                    String lastCommTm = sdf.format(new Date(node.getLastCommTm()));
+//
+//                    log.info("{}", String.format(
+//                            "%10s %4s %7s %19s %19s %9d %6d %19s  %s",
+//                            node.getKey(), check, connect, connectTm,
+//                            disconnectTm, node.getConnectCount().get(),
+//                            node.getDisconnectCount().get(), lastCommTm, info
+//                    ));
+//                });
+//
+        for (Map.Entry<Long, TsiNodeVo> obj : this.nodeManager.getTsiNodeVoMap().entrySet()) {
+            TsiNodeVo node = obj.getValue();
+            String check = (node.isInstalled() ? "Y" : "N");
+            check = check + (node.isSendNode() ? "Y" : "N");
+            check = check + (node.isSendTest() ? "Y" : "N");
+            check = check + (node.isSendCvim() ? "Y" : "N");
+            if (node.isRegistered()) {
+                registered++;
+            }
+            else {
+                unknown++;
+            }
+
+            String connect;
+            String info;
+            if (node.isConnect()) {
+                connected++;
+                connect = "Y";
+                info = NettyUtils.getRemoteAddress(node.getChannel());
+            }
+            else {
+                connect = "N";
+                info = "---";
+            }
+
+            String connectTm = sdf.format(new Date(node.getConnectTm()));
+            String disconnectTm = sdf.format(new Date(node.getDisconnectTm()));
+            String lastCommTm = sdf.format(new Date(node.getLastCommTm()));
+
+            log.info("{}", String.format("%10s %4s %7s %19s %19s %9d %6d %19s  %s", node.getKey(), check, connect, connectTm, disconnectTm, node.getConnectCount().get(), node.getDisconnectCount().get(), lastCommTm, info));
+        }
+        log.info("----------------------------------------------------------------------------------------------------------------");
+        log.info("Total Nodes: {} EA, Registered: {} EA, Unknown: {} EA, Connected: {} EA", nodeCount, registered, unknown, connected);
+        log.info("==============================================");
+
+        MDC.remove(fileName);
+        MDC.clear();
+    }
+
+    public void checkSessionTimeout(long timeout) {
+        final String fileName = "timeout";
+        MDC.put("report", fileName);
+
+        String connectTm;
+        String lastCommTm;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+        long currTm = System.currentTimeMillis();
+        for (Map.Entry<Long, TsiNodeVo> obj : this.nodeManager.getTsiNodeVoMap().entrySet()) {
+            TsiNodeVo node = obj.getValue();
+            if (node.isConnect()) {
+                if ((currTm - node.getLastCommTm()) > timeout) {
+                    try {
+                        AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                        alarm.setAlarmCode(TsiAlarmConfigVo.COMM_02);
+                        alarm.setAlarmTarget(node.getKey());
+                        alarm.setAlarmValue(NettyUtils.getRemoteIpAddress(node.getChannel()));
+                        this.dbmsProcess.add(alarm, (int) Thread.currentThread().getId());
+
+                        connectTm = sdf.format(new Date(node.getConnectTm()));
+                        lastCommTm = sdf.format(new Date(node.getLastCommTm()));
+                        log.info("Recv Timeout: Node: {}, Connect: {}, LastCommTime: {}, timeout: {}",
+                                node.getKey(), connectTm, lastCommTm, timeout);
+
+                        node.getChannel().disconnect();
+                        node.getChannel().close();
+                    }
+                    catch (Exception e) {
+                        log.error("checkSessionTimeout: {}", e.getMessage());
+                    }
+                }
+            }
+        }
+
+        MDC.remove(fileName);
+        MDC.clear();
+    }
+
+    public void reportQueueInfo() {
+        final String fileName = "queue";
+        MDC.put("report", fileName);
+
+        log.info("================================================================================================================");
+        log.info("Worker Queue Information.");
+        List<AbstractTsiCvimWorker> processWorkerList = this.packetProcess.getWorkerList();
+        log.info("----- Packet Worker: {} EA.", processWorkerList.size());
+        List<TsiCvimPacketWorker> packetWorkers = processWorkerList.stream()
+                .filter(worker -> worker instanceof TsiCvimPacketWorker)
+                .map(worker -> (TsiCvimPacketWorker) worker)
+                .collect(Collectors.toList());
+        for (TsiCvimPacketWorker worker : packetWorkers) {
+            log.info("{}, Total/Size/Remain: {}/{}/{}, Average: {}",
+                    worker.getIdx(),
+                    worker.getQSize(), worker.getDATA_QUEUE().size(), worker.getDATA_QUEUE().remainingCapacity(),
+                    TimeUtils.elapsedTimeStr(worker.getAvgTime()));
+        }
+
+        List<AbstractTsiCvimWorker> dbmsWorkerList = this.dbmsProcess.getWorkerList();
+        log.info("----- Dbms Worker: {} EA.", dbmsWorkerList.size());
+        List<TsiCvimDbmsWorker> dbmsWorkers = dbmsWorkerList.stream()
+                .filter(worker -> worker instanceof TsiCvimDbmsWorker)
+                .map(worker -> (TsiCvimDbmsWorker) worker)
+                .collect(Collectors.toList());
+        for (TsiCvimDbmsWorker worker : dbmsWorkers) {
+            log.info("{}, Total/Size/Remain: {}/{}/{}, Average: {}",
+                    worker.getIdx(),
+                    worker.getQSize(), worker.getDATA_QUEUE().size(), worker.getDATA_QUEUE().remainingCapacity(),
+                    TimeUtils.elapsedTimeStr(worker.getAvgTime()));
+        }
+
+        List<AbstractTsiCvimWorker> loggingWorkerList = this.loggingProcess.getWorkerList();
+        log.info("----- Logging Worker: {} EA.", loggingWorkerList.size());
+        List<TsiCvimLoggingWorker> loggingWorkers = loggingWorkerList.stream()
+                .filter(worker -> worker instanceof TsiCvimLoggingWorker)
+                .map(worker -> (TsiCvimLoggingWorker) worker)
+                .collect(Collectors.toList());
+        for (TsiCvimLoggingWorker worker : loggingWorkers) {
+            log.info("{}, Total/Size/Remain: {}/{}/{}, Average: {}",
+                    worker.getIdx(),
+                    worker.getQSize(), worker.getDATA_QUEUE().size(), worker.getDATA_QUEUE().remainingCapacity(),
+                    TimeUtils.elapsedTimeStr(worker.getAvgTime()));
+        }
+        log.info("----------------------------------------------------------------------------------------------------------------");
+        log.info("================================================================================================================");
+
+        MDC.remove(fileName);
+        MDC.clear();
+    }
+
+}

+ 8 - 23
src/main/java/com/tsi/comm/server/repository/TsiSessionManager.java

@@ -5,36 +5,24 @@ import com.tsi.app.common.xnet.NettyUtils;
 import com.tsi.comm.server.vo.TsiNodeVo;
 import io.netty.channel.Channel;
 import io.netty.util.AttributeKey;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 @Slf4j
+@RequiredArgsConstructor
+@Component
 public class TsiSessionManager {
 
     public static final AttributeKey<TsiNodeVo> TSI_NODE_ATTRIBUTE_KEY = AttributeKey.valueOf("TsiNode");
-
-    private static TsiSessionManager _instance = null;
-
-    public static TsiSessionManager getInstance() {
-        if (_instance == null) {
-            synchronized (TsiSessionManager.class) {
-                if (_instance == null)
-                    _instance = new TsiSessionManager();
-            }
-        }
-        return _instance;
-    }
-
-    private TsiSessionManager() {
-        this.sessions = new Counter();
-        this.channelNodeMap = new ConcurrentHashMap<>();
-    }
-
+    @Getter
     private volatile boolean serverRun;
-    private Counter sessions;
-    private ConcurrentHashMap<Channel, TsiNodeVo> channelNodeMap;
+    private final Counter sessions = new Counter();
+    private final ConcurrentHashMap<Channel, TsiNodeVo> channelNodeMap = new ConcurrentHashMap<>();
 
     public int add() {
         return (int) this.sessions.increment();
@@ -63,9 +51,6 @@ public class TsiSessionManager {
     public void stop() {
         this.serverRun = false;
     }
-    public boolean isServerRun() {
-        return this.serverRun;
-    }
 
     public void reportChannelSessions() {
         log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");

+ 24 - 37
src/main/java/com/tsi/comm/server/repository/TsiTpmsManager.java

@@ -1,6 +1,5 @@
 package com.tsi.comm.server.repository;
 
-import com.tsi.app.common.app.AppUtils;
 import com.tsi.app.common.utils.Counter;
 import com.tsi.app.common.xnet.NetUtils;
 import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
@@ -8,53 +7,41 @@ import com.tsi.comm.server.mybatis.vo.CommStatusVo;
 import com.tsi.comm.server.mybatis.vo.KafkaTransVo;
 import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
 import com.tsi.comm.server.protocol.TsiCpuPacket;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
 
 @Slf4j
+@RequiredArgsConstructor
+@Component
 public class TsiTpmsManager {
 
-    private static TsiTpmsManager _instance = null;
-
-    public static TsiTpmsManager getInstance() {
-        if (_instance == null) {
-            synchronized (TsiTpmsManager.class) {
-                if (_instance == null)
-                    _instance = new TsiTpmsManager();
-            }
-        }
-        return _instance;
-    }
-
-    private TsiTpmsManager() {
-        this.readTPS = new Counter();
-        this.readTPM = new Counter();
-        this.readTPD = new Counter();
-        this.readBPS = new Counter();
-        this.readBPM = new Counter();
-        this.readBPD = new Counter();
-        this.dbmsProcess = (TsiCvimDbmsProcess) AppUtils.getBean(TsiCvimDbmsProcess.class);
-        this.kafkaTransVo = new KafkaTransVo(AbstractDbmsVo.DBMS_KAFKA_TRANS_HS);
-        this.kafkaTransVo.setHostName(NetUtils.getHostName());
-    }
-
-    // DB Process Service
-    private TsiCvimDbmsProcess dbmsProcess;
+    private final TsiCvimDbmsProcess dbmsProcess;
+    private final TsiSessionManager sessionManager;
 
     // 패킷 수
-    private Counter readTPS;    // read transaction per seconds
-    private Counter readTPM;    // read transaction per minute
-    private Counter readTPD;    // read transaction per day
+    private final Counter readTPS = new Counter();    // read transaction per seconds
+    private final Counter readTPM = new Counter();    // read transaction per minute
+    private final Counter readTPD = new Counter();    // read transaction per day
 
     // 패킷 바이트수
-    private Counter readBPS;    // read bytes per seconds
-    private Counter readBPM;    // read bytes per minute
-    private Counter readBPD;    // read bytes per day
-    private KafkaTransVo kafkaTransVo;
+    private final Counter readBPS = new Counter();    // read bytes per seconds
+    private final Counter readBPM = new Counter();    // read bytes per minute
+    private final Counter readBPD = new Counter();    // read bytes per day
+
+    @Getter
+    private final KafkaTransVo kafkaTransVo = new KafkaTransVo(AbstractDbmsVo.DBMS_KAFKA_TRANS_HS);
 
-    public KafkaTransVo getKafkaTransVo() {
-        return kafkaTransVo;
+    @PostConstruct
+    void init() {
+        this.kafkaTransVo.setHostName(NetUtils.getHostName());
     }
 
+    // DB Process Service
+
     public void readPacket(TsiCpuPacket packet) {
         this.readTPS.increment();
         this.readBPS.add(packet.getBuf().length);
@@ -73,7 +60,7 @@ public class TsiTpmsManager {
         stat.setId(serverId);
         stat.setTrans(trans);
         stat.setBytes(bytes);
-        stat.setSessions(TsiSessionManager.getInstance().get());
+        stat.setSessions(this.sessionManager.get());
         this.dbmsProcess.add(stat, (int)Thread.currentThread().getId());
 
         /*log.info("Second Statistics: {} sessions, {} TRX, {}. {}",

+ 53 - 16
src/main/java/com/tsi/comm/server/scheduler/TsiCommScheduler.java

@@ -8,7 +8,7 @@ import com.tsi.comm.server.kafka.KafkaConsumerService;
 import com.tsi.comm.server.kafka.KafkaProducerService;
 import com.tsi.comm.server.mybatis.TsiDatabaseService;
 import com.tsi.comm.server.repository.TsiAlarmManager;
-import com.tsi.comm.server.repository.TsiNodeManager;
+import com.tsi.comm.server.repository.TsiReportManager;
 import com.tsi.comm.server.repository.TsiTpmsManager;
 import com.tsi.comm.server.vo.TsiAlarmConfigVo;
 import lombok.AllArgsConstructor;
@@ -18,8 +18,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PreDestroy;
-
 @Slf4j
 @EnableScheduling
 @AllArgsConstructor
@@ -28,25 +26,30 @@ public class TsiCommScheduler {
 
     private final TraceConfig trace;
     private final TsiCvimServerConfig config;
+    private final TsiReportManager reportManager;
+    private final TsiAlarmManager alarmManager;
+    private final TsiTpmsManager tpmsManager;
     private final TsiDatabaseService tsiDatabaseService;
     private final KafkaProducerService kafkaProducerService;
     private final KafkaConsumerService kafkaConsumerService;
 
-    @PreDestroy
-    public void onShutDown() {
-    }
-
     @Async
     @Scheduled(cron = "* * * * * *")  // 1초 주기 작업 실행
     public void staticsForPacketSecond() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         Elapsed elapsed = new Elapsed();
-        TsiTpmsManager.getInstance().resetSecond(this.config.getServerId());
+        this.tpmsManager.resetSecond(this.config.getServerId());
         log.info("{}", String.format("%25s: %s", "staticsForPacketSecond", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
     }
 
     @Async
     @Scheduled(cron = "0/5 * * * * *")  // 5초 주기 작업 실행
     public void checkKafkaServerAlive() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         Elapsed elapsed = new Elapsed();
         this.kafkaConsumerService.start();
         this.kafkaProducerService.sendPing();
@@ -56,12 +59,15 @@ public class TsiCommScheduler {
     @Async
     @Scheduled(cron = "0/5 * * * * *")  // 5초 주기 작업 실행
     public void checkSessionTimeout() {
-        if (!TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.COMM_02)) {
+        if (!this.config.isStartup()) {
+            return;
+        }
+        if (!this.alarmManager.checkAlarm(TsiAlarmConfigVo.COMM_02)) {
             return;
         }
         Elapsed elapsed = new Elapsed();
         long timeout = 0;
-        TsiAlarmConfigVo vo = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.COMM_02);
+        TsiAlarmConfigVo vo = this.alarmManager.get(TsiAlarmConfigVo.COMM_02);
         if (vo == null) return; // 이거면 안됌.
         timeout = vo.getValue() * 1000L;
 //        timeout *= 3; // 3배로 늘려서 체크
@@ -69,45 +75,76 @@ public class TsiCommScheduler {
             log.error("checkSessionTimeout: timeout value error: {}", timeout);
             return;
         }
-        TsiNodeManager.getInstance().checkSessionTimeout(timeout);
+        this.reportManager.checkSessionTimeout(timeout);
         log.info("{}", String.format("%25s: %s", "checkSessionTimeout", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
     }
 
     @Async
     @Scheduled(cron = "0/30 * * * * *")  // 30초 주기 작업 실행
     public void reportNodeSessionAlive() {
+        if (!this.config.isStartup()) {
+            return;
+        }
+        if (!this.trace.isSessionReport()) {
+            return; // 세션 정보 보고 안함.
+        }
         Elapsed elapsed = new Elapsed();
-        TsiNodeManager.getInstance().reportNodeSessions();
+        this.reportManager.reportNodeSessions();
 //        TsiSessionManager.getInstance().reportChannelSessions();
         log.info("{}", String.format("%25s: %s", "reportNodeSessionAlive", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
     }
 
+    @Async
+    @Scheduled(cron = "5/35 * * * * *")  // 30초 주기 작업 실행
+    public void reportQueueInformation() {
+        if (!this.config.isStartup()) {
+            return;
+        }
+        if (!this.trace.isQueueReport()) {
+            return; // 큐 정보 보고 안함.
+        }
+        Elapsed elapsed = new Elapsed();
+        this.reportManager.reportQueueInfo();
+        log.info("{}", String.format("%25s: %s", "reportQueueInformation", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
+    }
+
     @Async
     @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
     public void staticsForPacketMinute() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         Elapsed elapsed = new Elapsed();
-        TsiTpmsManager.getInstance().resetMinute();
+        this.tpmsManager.resetMinute();
         log.info("{}", String.format("%25s: %s", "staticsForPacketMinute", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
     }
 
-
     @Async
-    @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
+    @Scheduled(cron = "0/10 * * * * *")  // 1분 주기 작업 실행
     public void loadCommDump() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         this.trace.loadTraceInfo();
     }
 
     @Async
     @Scheduled(cron = "0 0 0 * * *")  // 1일 주기 작업 실행
     public void staticsForPacketDay() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         Elapsed elapsed = new Elapsed();
-        TsiTpmsManager.getInstance().resetDay();
+        this.tpmsManager.resetDay();
         log.info("{}", String.format("%25s: %s", "staticsForPacketDay", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
     }
 
     @Async
     @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
     public void loadBaseDatabase() {
+        if (!this.config.isStartup()) {
+            return;
+        }
         Elapsed elapsed = new Elapsed();
         this.tsiDatabaseService.loadDatabase();
         this.tsiDatabaseService.updateProcessState(1);

+ 43 - 14
src/main/java/com/tsi/comm/server/tcp/codec/CvimServerByteBufMessageDecoder.java

@@ -6,6 +6,7 @@ import com.tsi.app.common.xnet.NettyUtils;
 import com.tsi.comm.server.config.TsiCvimServerConfig;
 import com.tsi.comm.server.mybatis.vo.AbstractDbmsVo;
 import com.tsi.comm.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.comm.server.mybatis.vo.NodeIpAddrVo;
 import com.tsi.comm.server.mybatis.vo.NodeStatusVo;
 import com.tsi.comm.server.process.dbms.TsiCvimDbmsProcess;
 import com.tsi.comm.server.process.packet.TsiCvimPacketProcess;
@@ -34,11 +35,15 @@ import java.util.List;
 public class CvimServerByteBufMessageDecoder extends MessageToMessageDecoder<ByteBuf> {
 
     private final TsiCvimServerConfig config;
+    private final TsiNodeManager nodeManager;
+    private final TsiAlarmManager alarmManager;
+    private final TsiTpmsManager tpmsManager;
+    private final TsiSessionManager sessionManager;
     private final TsiCvimPacketProcess packetProcess;
     private final TsiCvimDbmsProcess dbmsProcess;
 
     @Override
-    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
+    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) {
         try {
             long msec = TimeUtils.currentTimeSeconds();
             long nsec = System.nanoTime();
@@ -56,13 +61,21 @@ public class CvimServerByteBufMessageDecoder extends MessageToMessageDecoder<Byt
                 return;
             }
 
+            final String remoteIpAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
+
             long nodeId = byteBuf.getUnsignedInt(6);
             TsiNodeVo nodeVo = ctx.channel().attr(TsiSessionManager.TSI_NODE_ATTRIBUTE_KEY).get();
             if (nodeVo == null) {
                 // not found node information from channel map
-                nodeVo = attachNodeVo(nodeId, ctx.channel());
+                nodeVo = attachNodeVo(nodeId, remoteIpAddress, ctx.channel());
                 if (nodeVo == null) {
                     // node id 가 0 이하로 설정되어 있거나, 노드 정보가 등록되어 있지 않은 경우
+                    if (nodeId <= 0) {
+                        byte[] buf = new byte[readableBytes];
+                        byteBuf.readBytes(buf);
+                        this.alarmManager.loggingUnknownNodePacket(nodeId, ctx.channel(), buf);
+                    }
+                    ctx.disconnect();
                     ctx.close();
                     return;
                 }
@@ -75,16 +88,26 @@ public class CvimServerByteBufMessageDecoder extends MessageToMessageDecoder<Byt
                 status.setNodeId(nodeId);
                 status.setStatus(1);
                 status.setIpAddr(NettyUtils.getRemoteIpAddress(ctx.channel()));
-                if (TsiSessionManager.getInstance().isServerRun()) {
+                if (this.sessionManager.isServerRun()) {
                     this.dbmsProcess.add(status, (int)Thread.currentThread().getId());
                 }
                 else {
-                    log.error("Node Login but server not running: {}", status.toString());
+                    log.error("Node Login but server not running: {}", status);
                 }
             }
 
             nodeVo.setLastCommTm(System.currentTimeMillis());   // 통신 수신시각 저장
 
+            if (!remoteIpAddress.equals(nodeVo.getIpAddr())) {
+                // IP 주소가 변경된 경우
+                nodeVo.setIpAddr(remoteIpAddress);
+
+                NodeIpAddrVo nodeIpAddrVo = new NodeIpAddrVo(AbstractDbmsVo.DBMS_NODE_IP_UPDATE);
+                nodeIpAddrVo.setNodeId(nodeVo.getNodeId());
+                nodeIpAddrVo.setIpAddr(remoteIpAddress);
+                this.dbmsProcess.add(nodeIpAddrVo, (int)Thread.currentThread().getId());
+            }
+
             TsiCpuPacket packet = new TsiCpuPacket(nodeId, msec, nsec, ctx.channel());
             packet.setBuf(new byte[readableBytes]);
             byteBuf.readBytes(packet.getBuf());
@@ -97,42 +120,48 @@ public class CvimServerByteBufMessageDecoder extends MessageToMessageDecoder<Byt
             packet.setAdd(System.nanoTime());
 
             // 패킷 통계정보 생성
-            TsiTpmsManager.getInstance().readPacket(packet);
+            this.tpmsManager.readPacket(packet);
             if (nodeVo.isDump()) {
                 log.info("RECV: {}, {}", nodeVo.getNodeId(), SysUtils.byteArrayToHex(packet.getBuf()));
             }
+//            if (nodeId <= 0) {
+//                // logging
+//                this.alarmManager.loggingUnknownNodePacket(nodeId, ctx.channel(), packet);
+//            }
         }
         catch (Exception e) {
             log.error("decode Exception: {}", e.getMessage());
         }
     }
 
-    private TsiNodeVo attachNodeVo(long nodeId, Channel channel) {
+    private TsiNodeVo attachNodeVo(long nodeId, String remoteIpAddress, Channel channel) {
         long start = System.nanoTime();
 
         // 노드맵에서 노드 정보를 찾는다.
-        TsiNodeVo nodeVo = TsiNodeManager.getInstance().get(nodeId);
+        TsiNodeVo nodeVo = this.nodeManager.get(nodeId);
         if (nodeVo == null) {
             // 메모리맵에 노드정보가 존재하지 않은 경우
             // 원래는 종료 시켜야 하나.....
             // 신규로 해당 노드정보 메로리를 생성해서 메모리 맵에 추가한다.
 
-            log.warn("The node ID of the first received packet is not registered..: {}, {}", nodeId, channel);
+            this.alarmManager.loggingUnknownNode(nodeId, channel);
+//            log.warn("The node ID of the first received packet is not registered..: {}, {}", nodeId, channel);
             if (nodeId <= 0) {
-                log.error("Node ID is set to 0 or less. Node ID: {}, Channel: {}", nodeId, channel);
                 return null; // 잘못된 노드 ID인 경우 null 반환
             }
-            nodeVo = new TsiNodeVo(nodeId, false, true, true);
+            nodeVo = new TsiNodeVo(nodeId, remoteIpAddress, false, true, true);
             nodeVo.setCheckInstalled(true);
             nodeVo.setRegistered(false);
-            TsiNodeManager.getInstance().put(nodeId, nodeVo);
+            this.nodeManager.put(nodeId, nodeVo);
+
+            this.alarmManager.loggingAddUnknownNode(nodeId, channel);
 
             // oops 알람 설정 되어 있으면 알람테이블에 저장하자.
-            if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.COMM_01)) {
+            if (this.alarmManager.checkAlarm(TsiAlarmConfigVo.COMM_01)) {
                 AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
                 alarm.setAlarmCode(TsiAlarmConfigVo.COMM_01);
                 alarm.setAlarmTarget(Long.toString(nodeId));
-                alarm.setAlarmValue(NettyUtils.getRemoteIpAddress(channel));
+                alarm.setAlarmValue(remoteIpAddress);
                 this.dbmsProcess.add(alarm, (int)Thread.currentThread().getId());
             }
         }
@@ -141,7 +170,7 @@ public class CvimServerByteBufMessageDecoder extends MessageToMessageDecoder<Byt
         nodeVo.setConnect(channel);
 
         // 채널 맵에 채널에 대한 노드정보를 저장한다.
-        TsiSessionManager.getInstance().addChannel(channel, nodeVo);
+        this.sessionManager.addChannel(channel, nodeVo);
 
         log.info("Node Object Register, Node: {}: {}, {}", nodeId, TimeUtils.elapsedTime(start), Thread.currentThread().getId());
         return nodeVo;

+ 14 - 8
src/main/java/com/tsi/comm/server/tcp/handler/CvimServerInboundMessageHandler.java

@@ -29,6 +29,8 @@ import org.springframework.stereotype.Component;
 public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapter {
 
     private final TsiCvimServerConfig config;
+    private final TsiSessionManager sessionManager;
+    private final TsiAlarmManager alarmManager;
     private final TsiCvimPacketProcess packetProcess;
     private final TsiCvimDbmsProcess dbmsProcess;
 
@@ -43,20 +45,22 @@ public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapte
         }
     }
 
+    @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         // session count increment
-        int sessions = TsiSessionManager.getInstance().add();
+        int sessions = this.sessionManager.add();
         // IP Address 로 제어기를 판달할 수 있으면 여기서 제어기 등록 여부를 판단해서
         // 접속 여부를 처리할 수 있다.
         log.info("{}.++channelActive: {}, {} Sessions.", this.getClass().getSimpleName(), NettyUtils.getAddress(ctx.channel()), sessions);
         ctx.fireChannelActive();
     }
 
+    @Override
     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        TsiNodeVo nodeVo = TsiSessionManager.getInstance().getNodeVo(ctx.channel());
+        TsiNodeVo nodeVo = this.sessionManager.getNodeVo(ctx.channel());
         if (nodeVo != null) {
             nodeVo.setConnect(null);
-            TsiSessionManager.getInstance().removeChannel(ctx.channel());
+            this.sessionManager.removeChannel(ctx.channel());
 
             // TODO: session disconnect. to be continue
             NodeStatusVo status = new NodeStatusVo(AbstractDbmsVo.DBMS_NODE_STATUS);
@@ -64,7 +68,7 @@ public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapte
             status.setNodeId(nodeVo.getNodeId());
             status.setStatus(0);
             status.setIpAddr(NettyUtils.getRemoteIpAddress(ctx.channel()));
-            if (TsiSessionManager.getInstance().isServerRun()) {
+            if (this.sessionManager.isServerRun()) {
                 TsiCpuDisconnected packet = new TsiCpuDisconnected(nodeVo.getNodeId(), ctx.channel());
                 packet.setBuf(null);
                 packet.setObj(nodeVo);
@@ -81,15 +85,16 @@ public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapte
         }
 
         // session count decrement
-        int sessions = TsiSessionManager.getInstance().remove();
+        int sessions = this.sessionManager.remove();
         log.info("{}.channelInactive: {}, {} Sessions.", this.getClass().getSimpleName(), NettyUtils.getAddress(ctx.channel()), sessions);
         ctx.fireChannelInactive();
     }
 
+    @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object e) throws Exception {
         if (e instanceof IdleStateEvent) {
             IdleStateEvent evt = (IdleStateEvent) e;
-            TsiNodeVo nodeVo = TsiSessionManager.getInstance().getNodeVo(ctx.channel());
+            TsiNodeVo nodeVo = this.sessionManager.getNodeVo(ctx.channel());
 //            if (nodeVo != null) {
 //                log.error("{}.userEventTriggered: {}, {}, {}", this.getClass().getSimpleName(), nodeVo.getNodeId(), ctx.channel(), evt.state().toString());
 //            }
@@ -98,7 +103,7 @@ public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapte
             if (evt.state() == IdleState.READER_IDLE) {
                 if (nodeVo == null) {
                     // 통신 접속 후 수신 데이터가 없이 READ 타임아웃이 발생한 경우임
-                    if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.COMM_02)) {
+                    if (this.alarmManager.checkAlarm(TsiAlarmConfigVo.COMM_02)) {
                         AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
                         alarm.setAlarmCode(TsiAlarmConfigVo.COMM_02);
                         alarm.setAlarmTarget(NettyUtils.getRemoteIpAddress(ctx.channel()));
@@ -121,8 +126,9 @@ public class CvimServerInboundMessageHandler extends ChannelInboundHandlerAdapte
         ctx.fireUserEventTriggered(e);
     }
 
+    @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        TsiNodeVo nodeVo = TsiSessionManager.getInstance().getNodeVo(ctx.channel());
+        TsiNodeVo nodeVo = this.sessionManager.getNodeVo(ctx.channel());
         if (nodeVo != null) {
             log.error("{}.exceptionCaught: {}, {}", this.getClass().getSimpleName(), nodeVo.getNodeId(), ctx.channel());
         }

+ 3 - 1
src/main/java/com/tsi/comm/server/vo/TsiNodeVo.java

@@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
 @Setter
 public class TsiNodeVo {
     private long nodeId;
+    private String ipAddr;
     private boolean sendTest;
     private boolean sendNode;
     private boolean sendCvim;
@@ -48,8 +49,9 @@ public class TsiNodeVo {
     private boolean dump;
     private int idx;
 
-    public TsiNodeVo(long nodeId, boolean sendTest, boolean sendNode, boolean sendCvim) {
+    public TsiNodeVo(long nodeId, String ipAddr, boolean sendTest, boolean sendNode, boolean sendCvim) {
         this.nodeId = nodeId;
+        this.ipAddr = ipAddr;
         this.sendTest = sendTest;
         this.sendNode = sendNode;
         this.sendCvim = sendCvim;

+ 5 - 3
src/main/resources/application.yml

@@ -93,14 +93,16 @@ spring:
       on-profile: dev
   datasource:
     mybatis:
-      jdbc-url: jdbc:mariadb://61.108.209.105:3306/cvim_db?characterEncoding=UTF-8&serverTimezone=Asia/Seoul
+      jdbc-url: jdbc:mariadb://115.91.94.42:13306/cvim_db?characterEncoding=UTF-8&serverTimezone=Asia/Seoul
+      username: cvim
+      password: 44Klctest$$
 
   data:
     mongodb:
-      host: 61.108.209.106
+      host: 172.24.0.40
       port: 27017
 
 application:
   kafka:
     producer:
-      bootstrap-servers: 61.108.209.105:9093
+      bootstrap-servers: 172.24.0.30:9092,172.24.0.31:9093,172.24.0.32:9094

+ 40 - 15
src/main/resources/logback-spring.xml

@@ -11,8 +11,10 @@
     <property name="LOG_FILE_NAME"             value="${PROJECT_NAME}.log"/>
     <property name="LOG_FILE_NAME_ERROR"       value="${PROJECT_NAME}.err.log"/>
     <property name="LOG_FILE_NAME_PATTERN"     value="%d{yyyyMMdd}_%i.log.gz"/>
+
     <property name="LOG_FILE_NAME_PROCESS"     value="process"/>
     <property name="LOG_FILE_NAME_RAW"         value="raw"/>
+
     <property name="LOG_FILE_NAME_SESSION"     value="session.log"/>
     <property name="LOG_FILE_NAME_SCHEDULE"    value="schedule.log"/>
     <property name="LOG_FILE_NAME_REPORT"      value="report.log"/>
@@ -20,9 +22,10 @@
     <property name="LOG_FILE_NAME_DBMS"        value="dbms.log"/>
     <property name="LOG_FILE_NAME_KAFKA"       value="kafka.log"/>
 
-    <property name="MAX_FILESIZE" value="100MB"/>
-    <property name="MAX_HISTORY"  value="30"/>
-    <property name="MAX_PROCESS_FILESIZE" value="20MB"/>
+    <property name="MAX_FILESIZE" value="20MB"/>
+    <property name="MAX_HISTORY"  value="15"/>
+    <property name="MAX_PROCESS_FILESIZE" value="10MB"/>
+
     <property name="LOG_PATTERN_FILE"        value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
     <property name="LOG_PATTERN_ERROR"       value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %msg%n"/>
     <property name="LOG_PATTERN_PROCESS"     value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
@@ -89,6 +92,7 @@
             </appender>
         </sift>
     </appender>
+
     <logger name="com.tsi.comm.server.process.packet" level="INFO" additivity="false">
         <appender-ref ref="FILE_PROCESS"/>
         <appender-ref ref="FILE_LOG"/>
@@ -101,6 +105,7 @@
     </logger>
 
     <root level="INFO">
+<!--        <appender-ref ref="CONSOLE"/>-->
         <appender-ref ref="FILE_LOG"/>
         <appender-ref ref="FILE_ERROR"/>
     </root>
@@ -178,22 +183,42 @@
     </appender>
 
     <logger name="com.tsi.comm.server.tcp" level="INFO" additivity="false">
-<!--        <appender-ref ref="CONSOLE"/>-->
         <appender-ref ref="FILE_SESSION"/>
         <appender-ref ref="FILE_ERROR"/>
     </logger>
 
-    <appender name="FILE_REPORT" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <file>${LOG_PATH}${LOG_FILE_NAME_REPORT}</file>
-        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
-            <charset>${LOG_CHARSET}</charset>
-            <pattern>${LOG_PATTERN_FILE}</pattern>
-        </encoder>
-        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
-            <fileNamePattern>${LOG_BACKUP_PATH}Schedule/${LOG_FILE_NAME_REPORT}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
-            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
-            <maxHistory>${MAX_HISTORY}</maxHistory>
-        </rollingPolicy>
+<!--    <appender name="FILE_REPORT" class="ch.qos.logback.core.rolling.RollingFileAppender">-->
+<!--        <file>${LOG_PATH}${LOG_FILE_NAME_REPORT}</file>-->
+<!--        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
+<!--            <charset>${LOG_CHARSET}</charset>-->
+<!--            <pattern>${LOG_PATTERN_FILE}</pattern>-->
+<!--        </encoder>-->
+<!--        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">-->
+<!--            <fileNamePattern>${LOG_BACKUP_PATH}Schedule/${LOG_FILE_NAME_REPORT}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>-->
+<!--            <maxFileSize>${MAX_FILESIZE}</maxFileSize>-->
+<!--            <maxHistory>${MAX_HISTORY}</maxHistory>-->
+<!--        </rollingPolicy>-->
+<!--    </appender>-->
+    <appender name="FILE_REPORT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <key>report</key>
+            <defaultValue>${LOG_FILE_NAME_REPORT}</defaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${report}" class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <file>${LOG_PATH}/${report}.log</file>
+                <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+                    <charset>${LOG_CHARSET}</charset>
+                    <Pattern>${LOG_PATTERN_PROCESS}</Pattern>
+                </encoder>
+
+                <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                    <FileNamePattern>${LOG_BACKUP_PATH}/${report}.${LOG_FILE_NAME_PATTERN}</FileNamePattern>
+                    <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+                    <maxHistory>${MAX_HISTORY}</maxHistory>
+                </rollingPolicy>
+            </appender>
+        </sift>
     </appender>
 
     <logger name="com.tsi.comm.server.repository" level="INFO" additivity="false">

+ 8 - 0
src/main/resources/mybatis/mapper/tsi-comm-server.xml

@@ -53,6 +53,14 @@
         ]]>
     </select>
 
+    <update id="updateNodeIpAddr" parameterType="com.tsi.comm.server.mybatis.vo.NodeIpAddrVo">
+    <![CDATA[
+        update tb_tsc_node
+        set ipaddr = #{node.ipAddr}
+        where nodeid = #{node.nodeId}
+        ]]>
+    </update>
+
     <insert id="insertNodeStatusInitialize">
     <![CDATA[
         insert into tb_tsc_node_status(nodeid, status, eventdt, serverid)