Commits

Marcin Gardias committed d92cc0c

BAM-12335: do not wait for pump when process is finished and the watchdog is not updated for more than 15s

Comments (0)

Files changed (1)

src/main/java/com/atlassian/utils/process/ExternalProcessImpl.java

 
     private static final Logger LOG = Logger.getLogger(ExternalProcessImpl.class);
     private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
+    private static long DEFAULT_POST_PROCESS_EXIT_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
 
     private AtomicBoolean canceled = new AtomicBoolean(false);
     private List<String> command;
     private File workingDir;
     private boolean useWindowsEncodingWorkaround;
 
+    private long postProcessExitTimeout = DEFAULT_POST_PROCESS_EXIT_TIMEOUT;
+
     /**
      * Process an external command.
      *
                 // block on the output pumps even when the process has already finished.
                 // this gives the output pumps the chance to finish processing any output
                 // still stuck in buffers
-                awaitPump(outputPump, checkTime);
-                awaitPump(errorPump, checkTime);
+                awaitPumpOrProcessWithTimeoutOnExit(outputPump, checkTime);
+                awaitPumpOrProcessWithTimeoutOnExit(errorPump, checkTime);
 
                 // don't block on the input pump when the process has already finished
                 awaitPumpOrProcess(inputPump, checkTime);
-            } while (!isTimedOut() && areOutputPumpsRunning() && !Thread.currentThread().isInterrupted());
+            } while (!isTimedOut() && areOutputPumpsRunning() && !Thread.currentThread().isInterrupted() && isAlive());
         } finally {
             if (Thread.currentThread().isInterrupted()) {
                 cancel();
         }
     }
 
+    private void awaitPumpOrProcessWithTimeoutOnExit(LatchedRunnable runnable, long latestTime)
+    {
+        if (runnable != null) {
+            boolean finished = false;
+            while (!finished && System.currentTimeMillis() < latestTime && isAlive() && !Thread.currentThread().isInterrupted()) {
+                long timeout = Math.min(postProcessExitTimeout, latestTime - System.currentTimeMillis());
+                if (timeout < 1) {
+                    timeout = 1;
+                }
+                finished = runnable.await(timeout);
+            }
+
+            //so the process ended but pump is still running let's give it a chance: 15s counting from the last watchdog reset
+            if (!isAlive() && !Thread.currentThread().isInterrupted() && !finished)
+            {
+                long timeout = lastWatchdogReset + postProcessExitTimeout - System.currentTimeMillis();
+                if (timeout < 1) {
+                    timeout = 1;
+                }
+                runnable.await(timeout);
+            }
+        }
+    }
+
     /**
      * Wait for the pump to finish.
      * @param runnable the runnable that is pumping the input/outputstream
 
     public void setIdleTimeout(long idleTimeout) {
         this.idleTimeout = idleTimeout;
+        postProcessExitTimeout = Math.min(idleTimeout, DEFAULT_POST_PROCESS_EXIT_TIMEOUT);
     }
 
     @Deprecated