This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a commit to branch feature/SLING-13037-shutdown-hook-windows
in repository 
https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git

commit adecffe1aff4aad2fe7ee87fca9618cb8c46e58f
Author: Stefan Seifert <[email protected]>
AuthorDate: Fri Dec 19 12:53:57 2025 +0100

    SLING-13037 Refactor process shutdown code to always distinguish between 
windows and non-windows environments
---
 .../maven/feature/launcher/ProcessTracker.java     | 55 +++++++++++++++++-----
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java 
b/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java
index 63fda7d..efa54e1 100644
--- a/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java
+++ b/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java
@@ -23,7 +23,10 @@ import javax.inject.Singleton;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
 import org.apache.maven.shared.utils.Os;
 import org.slf4j.Logger;
@@ -36,6 +39,30 @@ public class ProcessTracker {
     private static final Logger LOG = 
LoggerFactory.getLogger(ProcessTracker.class);
 
     static void stop(Process process) throws InterruptedException {
+        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+            stopWithDescendants(process, false);
+        } else {
+            stopDirectly(process, false);
+        }
+    }
+
+    static void stopForcibly(Process process) throws InterruptedException {
+        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+            stopWithDescendants(process, true);
+        } else {
+            stopDirectly(process, true);
+        }
+    }
+
+    /**
+     * Use this for non-windows OS only by stopping the process directly, not 
caring about descendants.
+     */
+    private static void stopDirectly(Process process, boolean forcibly) throws 
InterruptedException {
+        if (forcibly) {
+            LOG.debug("Forcibly destroy process: {}", process);
+            process.destroyForcibly();
+            return;
+        }
         LOG.debug("Destroy process: {}", process);
         process.destroy();
         boolean stopped = process.waitFor(30, TimeUnit.SECONDS);
@@ -51,7 +78,7 @@ public class ProcessTracker {
      * The Launcher is started from a .bat file, and killing the known process 
only kills the .bat process, not the spawned java process.
      * So we try to kill all descendant processes first.
      */
-    static void stopWithDescendants(Process process) throws 
InterruptedException {
+    private static void stopWithDescendants(Process process, boolean forcibly) 
throws InterruptedException {
         LOG.debug("Destroy process with descendants: {}", process);
 
         ProcessHandle processHandle = 
ProcessHandle.of(process.pid()).orElse(null);
@@ -60,7 +87,12 @@ public class ProcessTracker {
             return;
         }
 
-        processHandle.descendants().forEach(childProcess -> {
+        for (ProcessHandle childProcess : 
processHandle.descendants().collect(Collectors.toList())) {
+            if (forcibly) {
+                LOG.debug("Forcibly destroy child process: {}", childProcess);
+                childProcess.destroyForcibly();
+                return;
+            }
             LOG.debug("Destroy child process: {}", childProcess);
             childProcess.destroy();
             try {
@@ -70,12 +102,12 @@ public class ProcessTracker {
                     childProcess.destroyForcibly();
                 }
                 LOG.debug("Destroy child process finished: {}", childProcess);
-            } catch (Exception ex) {
+            } catch (TimeoutException | ExecutionException ex) {
                 LOG.error("Error while stopping child process {}: {}", 
childProcess, ex.getMessage(), ex);
             }
-        });
+        }
 
-        stop(process);
+        stopDirectly(process, forcibly);
     }
 
     private final Object sync = new Object();
@@ -98,7 +130,11 @@ public class ProcessTracker {
                             LOG.error(
                                     "Launch {} was not shut down! Destroying 
forcibly from shutdown hook.",
                                     entry.getKey());
-                            process.destroyForcibly();
+                            try {
+                                ProcessTracker.stopForcibly(process);
+                            } catch (InterruptedException e) {
+                                interrupt();
+                            }
                         }
                     }
                 });
@@ -116,11 +152,6 @@ public class ProcessTracker {
             LOG.warn("Process not found in process list, skip stopping: {}", 
id);
             return;
         }
-
-        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
-            stopWithDescendants(process);
-        } else {
-            stop(process);
-        }
+        ProcessTracker.stop(process);
     }
 }

Reply via email to