[ 
https://issues.apache.org/jira/browse/EXEC-121?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17801211#comment-17801211
 ] 

Gary D. Gregory commented on EXEC-121:
--------------------------------------

Hello [~Marcono1234]
Thank you for your report.
PRs on GitHub are welcome :-)


> Async execution does not guarantee that process destroyer is registered
> -----------------------------------------------------------------------
>
>                 Key: EXEC-121
>                 URL: https://issues.apache.org/jira/browse/EXEC-121
>             Project: Commons Exec
>          Issue Type: Bug
>    Affects Versions: 1.3
>            Reporter: Marcono1234
>            Priority: Minor
>
> h3. Bug
> When using one of the async {{Executor.execute}} methods, i.e. one taking an 
> {{ExecuteResultHandler}} argument, it is not guaranteed that the process 
> destroyer is registered.
> The reason for this is that launching of the process and registration of the 
> process destroyer is done already in the separate executor thread. So it is 
> possible that a race condition occurs where the process is currently 
> launching but in the mean time the JVM exits, so the process destroyer is 
> never registered and the process is therefore not destroyed.
> While I assume for normal use cases it is unlikely that the JVM exits right 
> after the process was launched, such situations could occur if a (possibly 
> unrelated) error occurs and the whole application should terminate. In such 
> cases it would probably be important that any launched process is destroyed 
> as well.
> h3. Example
> Here is a small example demonstrating this:
> {code}
> Executor e = new DaemonExecutor();
> e.setProcessDestroyer(new ShutdownHookProcessDestroyer());
> // This is to get the timing of this test right, that is, finish in `main` 
> right after process was launched
> CountDownLatch latch = new CountDownLatch(1);
> e.setStreamHandler(new PumpStreamHandler() {
>     @Override
>     public void start() {
>         latch.countDown();
>         try {
>             Thread.sleep(1000);
>         } catch (InterruptedException e) {
>             e.printStackTrace();
>         }
>         super.start();
>     }
> });
> CommandLine c = new CommandLine("notepad.exe"); // for Windows
> e.execute(c, new ExecuteResultHandler() {
>     @Override
>     public void onProcessFailed(ExecuteException e) {
>         e.printStackTrace();
>     }
>     @Override
>     public void onProcessComplete(int exitValue) {
>         System.out.println("Completed: " + exitValue);
>     }
> });
> latch.await();
> {code}
> This is a bit contrived to make sure it gets the timing right, but it can 
> also be reproduced with "real world" code. What happens is that Notepad is 
> launched, the JVM exits but Notepad remains open (= the bug).
> If you add for example a {{Thread.sleep(3000);}} at the end of {{main}} it 
> works as expected and Notepad is closed when the JVM exits.
> h3. Possible solution
> One solution might be to launch the process and register the process 
> destroyer outside the executor thread. This would also have the nice side 
> effect that execution fails fast if the process cannot even be launched in 
> the first place.
> But on the other hand it would probably slow down starting async execution 
> because it has to wait until the process is launched (though not until it 
> exits; that is still handled by the executor thread).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to