Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ping repeatedly from ping thread #383

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
76 changes: 52 additions & 24 deletions src/main/java/hudson/remoting/PingThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
* @since 1.170
*/
public abstract class PingThread extends Thread {
private static final long DEFAULT_TIMEOUT = TimeUnit.MINUTES.toMillis(1);
private static final long DEFAULT_INTERVAL = TimeUnit.MINUTES.toMillis(10);
private static final int DEFAULT_MAX_TIMEOUTS = 4;

private final Channel channel;

/**
Expand All @@ -61,24 +65,34 @@ public abstract class PingThread extends Thread {
*/
private final long interval;

public PingThread(Channel channel, long timeout, long interval) {
/**
* Tolerate max timeouts before assuming ping error.
*/
private final int maxTimeouts;

public PingThread(Channel channel, long timeout, long interval, int maxTimeouts) {
jeffret-b marked this conversation as resolved.
Show resolved Hide resolved
super("Ping thread for channel "+channel);
this.channel = channel;
this.timeout = timeout;
this.interval = interval;
this.maxTimeouts = maxTimeouts;
setDaemon(true);
setUncaughtExceptionHandler((t, e) -> {
LOGGER.log(Level.SEVERE, "Uncaught exception in PingThread " + t, e);
onDead(e);
});
}

public PingThread(Channel channel, long timeout, long interval) {
this(channel, timeout, interval, DEFAULT_MAX_TIMEOUTS);
}

public PingThread(Channel channel, long interval) {
this(channel, TimeUnit.MINUTES.toMillis(4), interval);
this(channel, DEFAULT_TIMEOUT, interval);
}

public PingThread(Channel channel) {
this(channel, TimeUnit.MINUTES.toMillis(10));
this(channel, DEFAULT_INTERVAL);
}

public void run() {
Expand Down Expand Up @@ -106,31 +120,45 @@ public void run() {

private void ping() throws IOException, InterruptedException {
LOGGER.log(Level.FINE, "pinging {0}", channel.getName());
Future<?> f = channel.callAsync(new Ping());

int timeouts = 0;
long start = System.currentTimeMillis();

long end = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout);
long remaining = end - System.nanoTime();

do {
LOGGER.log(Level.FINE, "waiting {0}s on {1}", new Object[] {TimeUnit.NANOSECONDS.toSeconds(remaining), channel.getName()});
try {
f.get(Math.max(1,remaining),TimeUnit.NANOSECONDS);
LOGGER.log(Level.FINE, "ping succeeded on {0}", channel.getName());
return;
} catch (ExecutionException e) {
if (e.getCause() instanceof RequestAbortedException)
return; // connection has shut down orderly.
onDead(e);
return;
} catch (TimeoutException e) {
// get method waits "at most the amount specified in the timeout",
// so let's make sure that it really waited enough
while (true) {
cpt1gl0 marked this conversation as resolved.
Show resolved Hide resolved
Future<?> f = channel.callAsync(new Ping());

long end = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout);
long remaining = end - System.nanoTime();

do {
LOGGER.log( Level.FINE, "waiting {0}s on {1}",
new Object[] {TimeUnit.NANOSECONDS.toSeconds(remaining), channel.getName()} );
try {
f.get(Math.max(1,remaining),TimeUnit.NANOSECONDS);
LOGGER.log(Level.FINE, "ping succeeded on {0}", channel.getName());
return;
} catch (ExecutionException e) {
if (e.getCause() instanceof RequestAbortedException)
return; // connection has shut down orderly.
onDead(e);
return;
} catch (TimeoutException e) {
// get method waits "at most the amount specified in the timeout",
// so let's make sure that it really waited enough
}
remaining = end - System.nanoTime();
} while(remaining>0);

if (++timeouts >= maxTimeouts) {
break;
}
remaining = end - System.nanoTime();
} while(remaining>0);

onDead(new TimeoutException("Ping started at "+start+" hasn't completed by "+System.currentTimeMillis()));//.initCause(e)
LOGGER.log(Level.WARNING, "ping timeout {0}/{1} on {2}",
new Object[] {timeouts, maxTimeouts, channel.getName()} );
}

onDead(new TimeoutException( String.format("Ping started at %d hasn't completed by %d",
start, System.currentTimeMillis()) ));
}

/**
Expand Down