192.168.9.165 hai 1 semana
pai
achega
f4fd8fbfd0

+ 63 - 26
src/main/java/com/fdkankan/scene/AppListener.java

@@ -13,7 +13,13 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.io.BufferedReader;
+import java.io.File;
 import java.io.InputStreamReader;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.concurrent.TimeUnit;
 
 @Component
 @Slf4j
@@ -62,9 +68,11 @@ public class AppListener implements ApplicationRunner {
 
                 // 检查目标 PID 是否存活
                 if (!checkPidExist(pid, 3, 200L)) {
-                    log.info("目标 PID 不存在,准备退出 SpringBoot 服务... pid={}", pid);
-                    shutdownApplication();
-                    break;
+                    log.info("pid未检测到,开始检查文件");
+                    if (!isAppAlive(fdkkLaserConfig.getBinPath() + File.separator + ".statusrc")) {
+                        shutdownApplication();
+                        break;
+                    }
                 }
             } catch (Exception e) {
                 log.error("PID 监听线程异常", e);
@@ -82,6 +90,45 @@ public class AppListener implements ApplicationRunner {
     }
 
     /**
+     * 判断应用是否存活(10秒心跳)
+     *
+     * @param filePath 心跳文件路径
+     * @return 存活返回 true,超时或异常返回 false
+     */
+    public static boolean isAppAlive(String filePath) {
+        File file = new File(filePath);
+
+        // 文件不存在,直接认为应用不存活
+        if (!file.exists()) {
+            return false;
+        }
+
+        long lastModified = file.lastModified();
+        long currentTime = System.currentTimeMillis();
+
+        long timeout = TimeUnit.SECONDS.toMillis(3);
+        boolean flag = (currentTime - lastModified) <= timeout;
+        if (!flag) {
+            LocalDateTime lastTime = LocalDateTime.ofInstant(
+                    Instant.ofEpochMilli(lastModified),
+                    ZoneId.systemDefault()
+            );
+
+            String formattedTime = lastTime.format(
+                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+            );
+
+            log.error(
+                    "心跳文件已超过 3 秒未更新,准备退出 SpringBoot 服务,文件路径:{},最后更新时间:{}",
+                    filePath,
+                    formattedTime
+            );
+        }
+        // 超过 10 秒未更新
+        return flag;
+    }
+
+    /**
      * 多次重试检查 PID 是否存活
      *
      * @param pid            进程 PID
@@ -108,9 +155,8 @@ public class AppListener implements ApplicationRunner {
      * 判断 PID 是否存活(Java 8,使用系统命令)
      */
     private boolean isProcessAlive(long pid) {
+        String pidStr = String.valueOf(pid);
         try {
-            String pidStr = String.valueOf(pid);
-
             // 防御:PID 必须为纯数字
             if (!pidStr.matches("\\d+")) {
                 log.error("非法 PID: {}", pidStr);
@@ -118,27 +164,18 @@ public class AppListener implements ApplicationRunner {
             }
 
             if (SystemUtil.getOsInfo().isWindows()) {
-                // Windows 使用 tasklist,使用 ProcessBuilder 避免命令注入
-                Process process = new ProcessBuilder("cmd", "/c",
-                        "tasklist", "/FI", "PID eq " + pidStr)
-                        .redirectErrorStream(true)
-                        .start();
+                // PowerShell 命令:Get-Process -Id PID
+                Process process = new ProcessBuilder(
+                        "powershell",
+                        "-Command",
+                        "Get-Process -Id " + pidStr + " | Out-Null"
+                ).redirectErrorStream(true).start();
 
-                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
-                    String line;
-                    while ((line = reader.readLine()) != null) {
-                        // 简单但更精确一点的匹配方式
-                        String trimmed = line.trim();
-                        if (trimmed.isEmpty()) {
-                            continue;
-                        }
-                        // 避免 123 和 9123 误匹配
-                        if (trimmed.matches(".*\\s" + pidStr + "\\s.*") || trimmed.endsWith(" " + pidStr)) {
-                            return true;
-                        }
-                    }
-                }
-                return false;
+                int exitCode = process.waitFor();
+
+                // exitCode == 0 → 进程存在
+                // exitCode != 0 → 进程不存在
+                return exitCode == 0;
             } else {
                 // Linux / Mac 使用 kill -0
                 Process process = new ProcessBuilder("kill", "-0", pidStr)
@@ -148,7 +185,7 @@ public class AppListener implements ApplicationRunner {
                 return exitCode == 0;
             }
         } catch (Exception e) {
-            log.error("检查进程存活状态失败,pid={}", pid, e);
+            log.error("检查进程存活状态失败,pid={}", pidStr, e);
             return false;
         }
     }

+ 7 - 2
src/main/java/com/fdkankan/scene/constant/CmdConstant.java

@@ -34,11 +34,16 @@ public class CmdConstant {
 
     public final static String MINIO_UTIL_RM_DIR = fdkkLaserConfig.buildCallPath + File.separator + "miniorm.sh  @target";
 
-    public final static String MK_LINK_DIR = "sudo ln -s /J  @Target @Link";
+    public static final String MK_LINK_DIR =
+            "LINK=\"@Link\"; LINK=${LINK%/}; mkdir -p $(dirname \"$LINK\") && ln -snf \"@Target\" \"$LINK\"";
 
     public final static String MK_LINK_DIR_WIN = "mklink /J @Link @Target";
 
-    public final static String MK_LINK_FILE = "sudo ln  @Target @Link";
+    public static final String MK_LINK_FILE =
+            "LINK=\"@Link\"; LINK=${LINK%/}; " +
+                    "mkdir -p \"$(dirname \"$LINK\")\" && " +
+                    "ln -snf \"@Target\" \"$LINK\"";
+
     public final static String MK_LINK_FILE_WIN = "mklink /H @Link @Target";
 
 

+ 3 - 3
src/main/java/com/fdkankan/scene/util/CmdBuildUtil.java

@@ -56,7 +56,7 @@ public class CmdBuildUtil {
     public static void BuildModelCommand(String inPath) {
         String buildModelCommandCmd = "";
         if (CmdBuildUtil.OS.isLinux()) {
-            buildModelCommandCmd = BASH + CmdConstant.BUILD_MODEL_COMMAND
+            buildModelCommandCmd =  CmdConstant.BUILD_MODEL_COMMAND
                     .replace("@inPath", inPath);
             CmdUtils.callLineSh(buildModelCommandCmd);
 
@@ -71,7 +71,7 @@ public class CmdBuildUtil {
     public static void Obj2Tiles(String inPath) {
         String checkLaserCmd = "";
         if (CmdBuildUtil.OS.isLinux()) {
-            checkLaserCmd = BASH + CmdConstant.OBJ2_TILES
+            checkLaserCmd =CmdConstant.OBJ2_TILES
                     .replace("@inPath", inPath);
             CmdUtils.callLineSh(checkLaserCmd);
         } else {
@@ -85,7 +85,7 @@ public class CmdBuildUtil {
     public static void potreeConverter(String param, String inPath, String outPath) {
         String potreeConverterCmd = "";
         if (CmdBuildUtil.OS.isLinux()) {
-            potreeConverterCmd = BASH + CmdConstant.POTREE_CONVERTER.replace("@param", param)
+            potreeConverterCmd =CmdConstant.POTREE_CONVERTER.replace("@param", param)
                     .replace("@inPath", inPath).replace("@outPath", outPath);
             CmdUtils.callLineSh(potreeConverterCmd);
         } else {

+ 38 - 9
src/main/java/com/fdkankan/scene/util/CmdUtils.java

@@ -2,6 +2,9 @@ package com.fdkankan.scene.util;
 
 import lombok.extern.slf4j.Slf4j;
 
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
 /**
  * Created by Xiewj on 2021/1/4 0004 14:53
  */
@@ -102,15 +105,41 @@ public class CmdUtils {
     private static void callLineSh(String command, Integer lineSize) {
         CmdUtils.log.info("cmd: " + command);
         try {
-            String[] cmd = new String[]{"/bin/sh", "-c", command};
-            Process process = Runtime.getRuntime().exec(cmd);
-            CmdUtils.log.info("开始运行");
-            StreamGobblerLine errorGobbler = new StreamGobblerLine(process.getErrorStream(), "ERROR");
-            errorGobbler.start();
-            // 200行打印一次日志
-            StreamGobblerLine outGobbler = new StreamGobblerLine(process.getInputStream(), "STDOUT", lineSize);
-            outGobbler.start();
-            process.waitFor();
+            ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
+            Process process = pb.start();
+
+            // 异步读 stdout
+            Thread outThread = new Thread(() -> {
+                try {
+                    BufferedReader br = new BufferedReader(
+                            new InputStreamReader(process.getInputStream()));
+                    String line;
+                    while ((line = br.readLine()) != null) {
+                        log.info(line);
+                    }
+                } catch (Exception ignored) {}
+            });
+
+            // 异步读 stderr
+            Thread errThread = new Thread(() -> {
+                try {
+                    BufferedReader br = new BufferedReader(
+                            new InputStreamReader(process.getErrorStream()));
+                    String line;
+                    while ((line = br.readLine()) != null) {
+                        log.error(line);
+                    }
+                } catch (Exception ignored) {}
+            });
+
+            outThread.start();
+            errThread.start();
+
+            int code = process.waitFor();   // 不会再卡死
+            outThread.join();
+            errThread.join();
+
+            log.info("Exit code = " + code);
         } catch (Exception e) {
             e.printStackTrace();
         }