Skip to content

Commit

Permalink
Merge pull request #186 from jglick/watching-JENKINS-52165
Browse files Browse the repository at this point in the history
[JENKINS-52165] Minor refinements for log push mode
  • Loading branch information
jglick authored Jul 28, 2023
2 parents 324450f + bfaf04b commit c48aa07
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
import java.util.logging.Logger;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.remoting.ChannelClosedException;
import java.io.EOFException;
import java.nio.channels.ClosedChannelException;
import java.util.stream.Stream;
import jenkins.MasterToSlaveFileCallable;
import jenkins.model.Jenkins;
import jenkins.security.MasterToSlaveCallable;
Expand Down Expand Up @@ -541,8 +545,8 @@ public FilePath getOutputFile(FilePath workspace) throws IOException, Interrupte
}

@Override public void watch(FilePath workspace, Handler handler, TaskListener listener) throws IOException, InterruptedException, ClassCastException {
workspace.act(new StartWatching(this, handler, listener));
LOGGER.log(Level.FINE, "started asynchronous watch in {0}", controlDir);
workspace.actAsync(new StartWatching(this, handler, listener));
LOGGER.log(Level.FINE, "started asynchronous watch in " + controlDir, new Throwable());
}

/**
Expand Down Expand Up @@ -576,6 +580,21 @@ private static class StartWatching extends MasterToSlaveFileCallable<Void> {

}

// TODO https://github.com/jenkinsci/remoting/pull/657

Check warning on line 583 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

private static boolean isClosedChannelException(Throwable t) {
if (t instanceof ClosedChannelException) {

Check warning on line 585 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 585 is only partially covered, 2 branches are missing
return true;

Check warning on line 586 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 586 is not covered by tests
} else if (t instanceof ChannelClosedException) {

Check warning on line 587 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 587 is only partially covered, 2 branches are missing
return true;

Check warning on line 588 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 588 is not covered by tests
} else if (t instanceof EOFException) {

Check warning on line 589 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 589 is only partially covered, 2 branches are missing
return true;

Check warning on line 590 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 590 is not covered by tests
} else if (t == null) {

Check warning on line 591 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 591 is only partially covered, 2 branches are missing
return false;

Check warning on line 592 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 592 is not covered by tests
} else {
return isClosedChannelException(t.getCause()) || Stream.of(t.getSuppressed()).anyMatch(FileMonitoringTask::isClosedChannelException);

Check warning on line 594 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 594 is only partially covered, 4 branches are missing
}
}

private static class Watcher implements Runnable {

private final FileMonitoringController controller;
Expand All @@ -585,6 +604,7 @@ private static class Watcher implements Runnable {
private final @CheckForNull Charset cs;

Watcher(FileMonitoringController controller, FilePath workspace, Handler handler, TaskListener listener) {
LOGGER.log(Level.FINE, "starting " + this, new Throwable());

Check warning on line 607 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 607 is not covered by tests
this.controller = controller;
this.workspace = workspace;
this.handler = handler;
Expand All @@ -611,7 +631,8 @@ private static class Watcher implements Runnable {
handler.output(utf8EncodedStream);
long newLocation = ch.position();
lastLocationFile.write(Long.toString(newLocation), null);
LOGGER.log(Level.FINER, "copied {0} bytes from {1}", new Object[] {newLocation - lastLocation, logFile});
long delta = newLocation - lastLocation;

Check warning on line 634 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 634 is not covered by tests
LOGGER.finer(() -> this + " copied " + delta + " bytes from " + logFile);

Check warning on line 635 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 635 is not covered by tests
}
}
if (exitStatus != null) {
Expand All @@ -621,7 +642,7 @@ private static class Watcher implements Runnable {
} else {
output = null;
}
LOGGER.log(Level.FINE, "exiting with code {0}", exitStatus);
LOGGER.fine(() -> this + " exiting with code " + exitStatus);

Check warning on line 645 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 645 is not covered by tests
handler.exited(exitStatus, output);
controller.cleanup(workspace);
} else {
Expand All @@ -636,7 +657,11 @@ private static class Watcher implements Runnable {
}
} catch (Exception x) {
// note that LOGGER here is going to the agent log, not master log
LOGGER.log(Level.WARNING, "giving up on watching " + controller.controlDir, x);
if (isClosedChannelException(x)) {

Check warning on line 660 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 660 is only partially covered, 2 branches are missing
LOGGER.warning(() -> this + " giving up on watching " + controller.controlDir);

Check warning on line 661 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 661 is not covered by tests
} else {
LOGGER.log(Level.WARNING, this + " giving up on watching " + controller.controlDir, x);

Check warning on line 663 in src/main/java/org/jenkinsci/plugins/durabletask/FileMonitoringTask.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 663 is not covered by tests
}
// Typically this will have been inside Handler.output, e.g.:
// hudson.remoting.ChannelClosedException: channel is already closed
// at hudson.remoting.Channel.send(Channel.java:667)
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/org/jenkinsci/plugins/durabletask/Handler.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
import java.io.Serializable;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.remoting.Asynchronous;
import org.jenkinsci.remoting.SerializableOnlyOverRemoting;

/**
* A remote handler which may be sent to an agent and handle process output and results.
* If it needs to communicate with the master, you may use {@link VirtualChannel#export}.
* @see Controller#watch
*/
public abstract class Handler implements Serializable { // TODO 2.107+ SerializableOnlyOverRemoting
public abstract class Handler implements SerializableOnlyOverRemoting {

/**
* Notification that new process output is available.
Expand All @@ -60,8 +62,8 @@ public abstract class Handler implements Serializable { // TODO 2.107+ Serializa
* you still need to occasionally poll for an exit status from the master.
* @param code the exit code, if known (0 conventionally represents success); may be negative for anomalous conditions such as a missing process
* @param output standard output captured, if {@link DurableTask#captureOutput} was called; else null
* @throws Exception if anything goes wrong, this watch is deactivated
*/
@Asynchronous
public abstract void exited(int code, @Nullable byte[] output) throws Exception;

}

0 comments on commit c48aa07

Please sign in to comment.