From a200ec814b17e514f25f2c663d9685a43411d74c Mon Sep 17 00:00:00 2001 From: Joe Lauer Date: Mon, 4 Nov 2024 13:53:24 -0500 Subject: [PATCH] Ignore process exit code for exec() if JVM is shutting down --- .../com/fizzed/blaze/local/LocalExec.java | 27 ++++++++++++++++--- .../com/fizzed/blaze/util/ProcessReaper.java | 8 ++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/blaze-core/src/main/java/com/fizzed/blaze/local/LocalExec.java b/blaze-core/src/main/java/com/fizzed/blaze/local/LocalExec.java index 4ee90b69..d8f449b4 100644 --- a/blaze-core/src/main/java/com/fizzed/blaze/local/LocalExec.java +++ b/blaze-core/src/main/java/com/fizzed/blaze/local/LocalExec.java @@ -27,6 +27,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import com.fizzed.blaze.core.UnexpectedExitValueException; import com.fizzed.blaze.util.CommandLines; import com.fizzed.blaze.util.ProcessReaper; import org.zeroturnaround.exec.InvalidExitValueException; @@ -185,10 +186,28 @@ public void stop() { } finally { ProcessReaper.INSTANCE.unregister(startedProcess.getProcess()); } - } catch (InvalidExitValueException e) { - throw new com.fizzed.blaze.core.UnexpectedExitValueException("Process exited with unexpected value", this.exitValues, e.getExitValue()); - } catch (IOException | InterruptedException | ExecutionException e) { - throw new BlazeException("Unable to cleanly execute process", e); + } catch (Throwable t) { + if (t instanceof ExecutionException) { + ExecutionException ee = (ExecutionException)t; + if (ee.getCause() instanceof InvalidExitValueException) { + // this is actually what we want to process + t = ee.getCause(); + } + } + + if (t instanceof InvalidExitValueException) { + InvalidExitValueException ievae = (InvalidExitValueException)t; + + // this can happen IF we're in the process of being shutdown and we actually don't want to throw an exception + if (ProcessReaper.INSTANCE.isShuttingDown()) { + log.trace("Shutting down, ignoring invalid exit code on exec()"); + return new Exec.Result(this, ievae.getExitValue()); + } + + throw new UnexpectedExitValueException("Process exited with unexpected value", this.exitValues, ievae.getExitValue()); + } + + throw new BlazeException("Unable to cleanly execute process", t); } finally { // close all the output streams (input stream closed above) Streamables.close(os); diff --git a/blaze-core/src/main/java/com/fizzed/blaze/util/ProcessReaper.java b/blaze-core/src/main/java/com/fizzed/blaze/util/ProcessReaper.java index ad87aeb5..a3ede13f 100644 --- a/blaze-core/src/main/java/com/fizzed/blaze/util/ProcessReaper.java +++ b/blaze-core/src/main/java/com/fizzed/blaze/util/ProcessReaper.java @@ -13,12 +13,14 @@ public class ProcessReaper { private boolean shutdownHookAdded; private final Set processes; private final ReentrantLock lock; + private volatile boolean shuttingDown; static public final ProcessReaper INSTANCE = new ProcessReaper(); public ProcessReaper() { this.processes = new HashSet<>(); this.lock = new ReentrantLock(); + this.shuttingDown = false; } public void register(Process process) { @@ -45,8 +47,14 @@ public void unregister(Process process) { } } + public boolean isShuttingDown() { + return shuttingDown; + } + private Thread newShutdownThread() { return new Thread(() -> { + // flag to indicate we are now shutting down (which can help not throw exceptions in some cases) + this.shuttingDown = true; if (!this.processes.isEmpty()) { log.debug("Will destroy {} process(es) along with its children (to properly cleanup what we started)", this.processes.size()); ProcessHelper processHelper = ProcessHelper.get();