提交 e7fbce37 编写于 作者: A apetres 提交者: Oleg Nenashev

Allow disabling process killing on interruption (#3293)

* Allow disabling process killing on interuption

Plugins may want to do custom action when the execution of a remote process is interrupted. Currently it is not possible, because
the process started on a slave is killed on interruption.
My actual use case: https://groups.google.com/forum/#!msg/jenkinsci-dev/s6IkynOzdqE/2eFNKN9lAAAJ

My solution is to have a flag called killWhenInterrupted, set by default to true, which prevents process killing on the slave when unset.

* Invert killWhenInterrupted flag

* Add javadoc
上级 3fc39210
......@@ -181,6 +181,12 @@ public abstract class Launcher {
*/
protected boolean reverseStdin, reverseStdout, reverseStderr;
/**
* True to prevent killing the launched process when it is interrupted
* @since TODO
*/
protected boolean dontKillWhenInterrupted;
/**
* Passes a white-space separated single-string command (like "cat abc def") and parse them
* as a command argument. This method also handles quotes.
......@@ -441,6 +447,22 @@ public abstract class Launcher {
return this;
}
/**
* Indicates that the launched process should not be killed when interrupted.
* It allows detecting the interruption on caller's side and do custom (cleanup) action while
* the launched process is still running.
*
* <p>
* Note that the process can (and should) be killed
* via {@link Proc#kill()} when custom action is done.
*
* @return {@code this}
* @since TODO
*/
public ProcStarter dontKillWhenInterrupted() {
this.dontKillWhenInterrupted = true;
return this;
}
/**
* Starts the new process as configured.
......@@ -926,7 +948,7 @@ public abstract class Launcher {
ps.reverseStdin ?LocalProc.SELFPUMP_INPUT:ps.stdin,
ps.reverseStdout?LocalProc.SELFPUMP_OUTPUT:ps.stdout,
ps.reverseStderr?LocalProc.SELFPUMP_OUTPUT:ps.stderr,
toFile(ps.pwd));
toFile(ps.pwd), ps.dontKillWhenInterrupted);
}
private File toFile(FilePath f) {
......@@ -1049,7 +1071,8 @@ public abstract class Launcher {
final String workDir = psPwd==null ? null : psPwd.getRemote();
try {
return new ProcImpl(getChannel().call(new RemoteLaunchCallable(ps.commands, ps.masks, ps.envs, in, ps.reverseStdin, out, ps.reverseStdout, err, ps.reverseStderr, ps.quiet, workDir, listener)));
return new ProcImpl(getChannel().call(new RemoteLaunchCallable(ps.commands, ps.masks, ps.envs, in, ps.reverseStdin,
out, ps.reverseStdout, err, ps.reverseStderr, ps.quiet, workDir, listener, ps.dontKillWhenInterrupted)));
} catch (InterruptedException e) {
throw (IOException)new InterruptedIOException().initCause(e);
}
......@@ -1267,12 +1290,14 @@ public abstract class Launcher {
private final @Nonnull TaskListener listener;
private final boolean reverseStdin, reverseStdout, reverseStderr;
private final boolean quiet;
RemoteLaunchCallable(@Nonnull List<String> cmd, @CheckForNull boolean[] masks, @CheckForNull String[] env,
@CheckForNull InputStream in, boolean reverseStdin,
@CheckForNull OutputStream out, boolean reverseStdout,
@CheckForNull OutputStream err, boolean reverseStderr,
boolean quiet, @CheckForNull String workDir, @Nonnull TaskListener listener) {
private final boolean dontKillWhenInterrupted;
RemoteLaunchCallable(@Nonnull List<String> cmd, @CheckForNull boolean[] masks, @CheckForNull String[] env,
@CheckForNull InputStream in, boolean reverseStdin,
@CheckForNull OutputStream out, boolean reverseStdout,
@CheckForNull OutputStream err, boolean reverseStderr,
boolean quiet, @CheckForNull String workDir,
@Nonnull TaskListener listener, boolean dontKillWhenInterrupted) {
this.cmd = new ArrayList<>(cmd);
this.masks = masks;
this.env = env;
......@@ -1285,6 +1310,7 @@ public abstract class Launcher {
this.reverseStdout = reverseStdout;
this.reverseStderr = reverseStderr;
this.quiet = quiet;
this.dontKillWhenInterrupted = dontKillWhenInterrupted;
}
public RemoteProcess call() throws IOException {
......@@ -1295,6 +1321,7 @@ public abstract class Launcher {
if (reverseStdin) ps.writeStdin();
if (reverseStdout) ps.readStdout();
if (reverseStderr) ps.readStderr();
if (dontKillWhenInterrupted) ps.dontKillWhenInterrupted();
final Proc p = ps.start();
......
......@@ -64,6 +64,12 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
public abstract class Proc {
protected Proc() {}
/**
* Indicates that the process should not be killed on interruption.
* @since TODO
*/
protected boolean dontKillWhenInterrupted;
/**
* Checks if the process is still alive.
*/
......@@ -207,17 +213,17 @@ public abstract class Proc {
}
public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out, File workDir) throws IOException {
this(cmd,env,in,out,null,workDir);
this(cmd,env,in,out,null,workDir, true);
}
/**
* @param err
* null to redirect stderr to stdout.
*/
public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out,OutputStream err,File workDir) throws IOException {
public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out,OutputStream err,File workDir, boolean dontKillWhenInterrupted) throws IOException {
this( calcName(cmd),
stderr(environment(new ProcessBuilder(cmd),env).directory(workDir), err==null || err== SELFPUMP_OUTPUT),
in, out, err );
in, out, err, dontKillWhenInterrupted);
}
private static ProcessBuilder stderr(ProcessBuilder pb, boolean redirectError) {
......@@ -237,10 +243,11 @@ public abstract class Proc {
return pb;
}
private LocalProc( String name, ProcessBuilder procBuilder, InputStream in, OutputStream out, OutputStream err ) throws IOException {
private LocalProc( String name, ProcessBuilder procBuilder, InputStream in, OutputStream out, OutputStream err, boolean dontKillWhenInterrupted ) throws IOException {
Logger.getLogger(Proc.class.getName()).log(Level.FINE, "Running: {0}", name);
this.name = name;
this.out = out;
this.dontKillWhenInterrupted = dontKillWhenInterrupted;
this.cookie = EnvVars.createCookie();
procBuilder.environment().putAll(cookie);
if (procBuilder.directory() != null && !procBuilder.directory().exists()) {
......@@ -354,7 +361,9 @@ public abstract class Proc {
return r;
} catch (InterruptedException e) {
// aborting. kill the process
destroy();
if (!dontKillWhenInterrupted) {
destroy();
}
throw e;
} finally {
t.setName(oldName);
......@@ -462,7 +471,9 @@ public abstract class Proc {
return process.get();
} catch (InterruptedException e) {
LOGGER.log(Level.FINE, String.format("Join operation has been interrupted for the process %s. Killing the process", this), e);
kill();
if (!dontKillWhenInterrupted) {
kill();
}
throw e;
} catch (ExecutionException e) {
if(e.getCause() instanceof IOException)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册