luhaowen 5 napja
szülő
commit
0bb37737e9
1 módosított fájl, 63 hozzáadás és 17 törlés
  1. 63 17
      vars/deployJar.groovy

+ 63 - 17
vars/deployJar.groovy

@@ -1,23 +1,25 @@
 #!/usr/bin/env groovy
 /**
- * 强验证发布 SpringBoot  fat-jar
- *  - 按端口杀进程
- *  - 按 profile 做所有进程级校验
+ * 强验证发布 SpringBoot  fat-jar
+ * - 按端口杀进程
+ * - 按 profile 做所有进程级校验
  */
 def call(Map args = [:]) {
-    String jarName      = args.jarName      ?: env.JAR_NAME
-    String jarPath      = args.jarPath      ?: env.JAR_PATH
-    String remoteHost   = args.remoteHost   ?: env.REMOTE_HOST
-    String remotePort   = args.remotePort   ?: env.REMOTE_PORT
-    String remotePath   = args.remotePath   ?: env.REMOTE_PATH
-    String profile      = args.profile      ?: env.PROFILE
-    String jvmArgs      = args.jvmArgs      ?: env.JVM_ARGS ?: ''
+    String jarName      = args.jarName       ?: env.JAR_NAME
+    String jarPath      = args.jarPath       ?: env.JAR_PATH
+    String remoteHost   = args.remoteHost    ?: env.REMOTE_HOST
+    String remotePort   = args.remotePort    ?: env.REMOTE_PORT
+    String remotePath   = args.remotePath    ?: env.REMOTE_PATH
+    String profile      = args.profile       ?: env.PROFILE
+    String jvmArgs      = args.jvmArgs       ?: env.JVM_ARGS ?: ''
     String remoteJar    = "${remotePath}/${jarName}"
 
     PrintMes("开始发布 ${jarName} [profile=${profile}] 到 ${remoteHost}:${remotePort}", 'yellow')
 
     try {
+        
         /* 1. 按端口杀旧进程,并确认端口已释放 */
+        PrintMes("→ 1. 开始清理旧进程,确保端口 ${remotePort} 释放", 'yellow')
         sh """
             ssh -o StrictHostKeyChecking=no ${remoteHost} '
                 OLD_PID=\$(lsof -ti:${remotePort} || true)
@@ -32,55 +34,99 @@ def call(Map args = [:]) {
                 fi
             '
         """
+        PrintMes("√ 1. 旧进程清理完成,端口 ${remotePort} 已释放", 'yellow')
+        
 
         /* 2. 备份旧包 */
+        PrintMes("→ 2. 开始备份旧 JAR 包 ${remoteJar}", 'yellow')
         sh """
             ssh -o StrictHostKeyChecking=no ${remoteHost} '
                 test -f ${remoteJar} && mv ${remoteJar} ${remoteJar}-\$(date +%Y%m%d%H%M) || true
             '
         """
+        PrintMes("√ 2. 旧 JAR 包备份完成", 'yellow')
+
 
         /* 3. 传包 + MD5 强校验 */
+        PrintMes("→ 3. 开始传输 JAR 包并进行 MD5 强校验", 'yellow')
+        
         // 1. 在本地计算 MD5
         String localMd5 = sh(script: "md5sum ${jarPath} | awk '{print \$1}'", returnStdout: true).trim()
+        PrintMes("   本地 MD5: ${localMd5}", 'yellow')
 
         // 2. 传输 JAR 包
         sh "scp -o StrictHostKeyChecking=no ${jarPath} ${remoteHost}:${remoteJar}"
 
-        // 3. 远程计算 MD5 并返回(Jenkins Pipeline 会自动修剪输出)
+        // 3. 远程计算 MD5 并返回
         String remoteMd5Output = sh(
-         script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'md5sum ${remoteJar}'", 
-         returnStdout: true
+          script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'md5sum ${remoteJar}'", 
+          returnStdout: true
         ).trim()
 
         // 4. 在 Jenkins Groovy 侧处理输出,提取 MD5 值
-        // 输出格式通常是 "MD5_SUM FILENAME"。我们只需要第一个字段。
         String remoteMd5 = remoteMd5Output.split('\\s+')[0] 
+        PrintMes("   远程 MD5: ${remoteMd5}", 'yellow')
 
         if (localMd5 != remoteMd5) {
+            PrintMes("× 3. MD5 校验失败:本地 ${localMd5} != 远程 ${remoteMd5}", 'red')
             error("MD5 校验失败:本地 ${localMd5} != 远程 ${remoteMd5}")
         }
+        PrintMes("√ 3. JAR 包传输和 MD5 校验成功", 'yellow')
 
+        
         /* 4. 启动新进程 */
+        PrintMes("→ 4. 启动新进程 (profile=${profile})", 'yellow')
         sh """ssh -o StrictHostKeyChecking=no ${remoteHost} "sh -c 'cd ${remotePath} && nohup java ${jvmArgs} -jar ${jarName} --spring.profiles.active=${profile} > server.log 2>&1 &'" """
+        PrintMes("√ 4. 新进程启动命令已发送", 'yellow')
+
 
         /* 5. 按 profile 精确校验:有且仅有 1 个进程 */
+        PrintMes("→ 5. 校验进程数量 (期望 1 个 ${profile} 进程)", 'yellow')
         String procCount = sh(
             script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'ps -ef | grep \"java.*${jarName}.*--spring.profiles.active=${profile}\" | grep -v grep | wc -l'",
             returnStdout: true
         ).trim()
+        PrintMes("   实际找到 ${procCount} 个进程", 'yellow')
+
         if (procCount != "1") {
+            PrintMes("× 5. 启动校验失败:期望 1 个 ${profile} 进程,实际 ${procCount} 个", 'red')
             error("启动校验失败:期望 1 个 ${profile} 进程,实际 ${procCount} 个")
         }
+        PrintMes("√ 5. 进程数量校验成功", 'yellow')
+
 
-        /* 6. 端口已被新进程占用 */
-        String newPid = sh(script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'lsof -ti:${remotePort}'", returnStdout: true).trim()
+        /* 6. 端口已被新进程占用 (加入等待重试机制) */
+        def maxRetries = 12 // 最多重试 12 次
+        def waitTimeSec = 5 // 每次间隔 5 秒
+        String newPid = ""
+        
+        PrintMes("→ 6. 校验端口 ${remotePort} 是否已被新进程监听 (最大等待 ${maxRetries * waitTimeSec} 秒)", 'yellow')
+
+        for (int i = 0; i < maxRetries; i++) {
+            newPid = sh(script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'lsof -ti:${remotePort} || true'", returnStdout: true).trim()
+            
+            if (newPid) {
+                PrintMes("   端口已监听,PID: ${newPid}", 'yellow')
+                break // 找到 PID,跳出循环
+            }
+            
+            if (i < maxRetries - 1) {
+                PrintMes("   未监听,等待 ${waitTimeSec} 秒后重试... (${i + 1}/${maxRetries})", 'yellow')
+                sleep(waitTimeSec) // Jenkins Pipeline 内置步骤
+            }
+        }
+        
         if (!newPid) {
-            error("端口 ${remotePort} 未被新进程监听,启动可能失败")
+            PrintMes("× 6. 端口 ${remotePort} 在 ${maxRetries * waitTimeSec} 秒内未被新进程监听,启动可能失败", 'red')
+            error("端口 ${remotePort} 未被新进程监听,启动超时失败")
         }
+        PrintMes("√ 6. 端口监听校验成功", 'yellow')
+
 
+        // 最终成功提示
         PrintMes("发布成功 ${jarName} [profile=${profile}, pid=${newPid}]", 'green')
     } catch (Exception e) {
+        // 捕获异常,打印红色失败信息
         PrintMes("发布失败 ${jarName} : ${e.message}", 'red')
         error('deploySpringBoot failed')
     }