Skip to content

Commit 18327e9

Browse files
nparrykohsuke
authored andcommitted
[FIXED JENKINS-8990] Configurable ping interval
This lets you configure the ping interval for slaves via a system property. (hudson.slaves.ChannelPinger.pingInterval) The default ping interval has been lowered from 10 to 5 minutes. It also moves the ping setup logic into a ComputerListener (out of the JNLP slave Engine class). As a side effect, all slaves will now have a ping instead of just JNLP slaves.
1 parent 67cd5b4 commit 18327e9

File tree

2 files changed

+108
-16
lines changed

2 files changed

+108
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package hudson.slaves;
2+
3+
import hudson.Extension;
4+
import hudson.FilePath;
5+
import hudson.model.Computer;
6+
import hudson.model.Slave;
7+
import hudson.model.TaskListener;
8+
import hudson.remoting.Callable;
9+
import hudson.remoting.Channel;
10+
import hudson.remoting.PingThread;
11+
12+
import java.io.IOException;
13+
import java.util.concurrent.atomic.AtomicBoolean;
14+
import java.util.logging.Logger;
15+
16+
/**
17+
* Establish a periodic ping to keep connections between {@link Slave slaves}
18+
* and the main Jenkins node alive. This prevents network proxies from
19+
* terminating connections that are idle for too long.
20+
*/
21+
@Extension
22+
public class ChannelPinger extends ComputerListener {
23+
private static final Logger LOGGER = Logger.getLogger(ChannelPinger.class.getName());
24+
private static final String SYS_PROPERTY_NAME = ChannelPinger.class.getName() + ".pingInterval";
25+
26+
/**
27+
* Interval for the ping in minutes.
28+
*/
29+
private int pingInterval = 5;
30+
31+
public ChannelPinger() {
32+
String interval = System.getProperty(SYS_PROPERTY_NAME);
33+
if (interval != null) {
34+
try {
35+
pingInterval = Integer.valueOf(interval);
36+
} catch (NumberFormatException e) {
37+
LOGGER.warning("Ignoring invalid " + SYS_PROPERTY_NAME + "=" + interval);
38+
}
39+
}
40+
}
41+
42+
@Override
43+
public void preOnline(Computer c, Channel channel, FilePath root, TaskListener listener) {
44+
if (pingInterval < 1) {
45+
LOGGER.fine("Slave ping is disabled");
46+
return;
47+
}
48+
49+
try {
50+
channel.call(new SetUpRemotePing(pingInterval));
51+
LOGGER.fine("Set up a remote ping for " + c.getName());
52+
} catch (Exception e) {
53+
LOGGER.severe("Failed to set up a ping for " + c.getName());
54+
}
55+
56+
// TODO: Set up a local to remote ping too?
57+
// If we just want to keep some activity on the channel this doesn't
58+
// matter, but if we consider the ping a 'are you alive?' check it
59+
// might be useful.
60+
//setUpPingForChannel(channel, pingInterval);
61+
}
62+
63+
private static class SetUpRemotePing implements Callable<Void, IOException> {
64+
private static final long serialVersionUID = -2702219700841759872L;
65+
private int pingInterval;
66+
public SetUpRemotePing(int pingInterval) {
67+
this.pingInterval = pingInterval;
68+
}
69+
70+
@Override
71+
public Void call() throws IOException {
72+
setUpPingForChannel(Channel.current(), pingInterval);
73+
return null;
74+
}
75+
}
76+
77+
private static void setUpPingForChannel(final Channel channel, int interval) {
78+
final AtomicBoolean isInClosed = new AtomicBoolean(false);
79+
final PingThread t = new PingThread(channel, interval * 60 * 1000) {
80+
protected void onDead() {
81+
try {
82+
if (isInClosed.get()) {
83+
LOGGER.fine("Ping failed after socket is already closed");
84+
}
85+
else {
86+
LOGGER.info("Ping failed. Terminating the socket.");
87+
channel.close();
88+
}
89+
} catch (IOException e) {
90+
LOGGER.severe("Failed to terminate the socket: " + e);
91+
}
92+
}
93+
};
94+
95+
channel.addListener(new Channel.Listener() {
96+
@Override
97+
public void onClosed(Channel channel, IOException cause) {
98+
LOGGER.fine("Terminating ping thread for " + channel);
99+
isInClosed.set(true);
100+
t.interrupt(); // make sure the ping thread is terminated
101+
}
102+
});
103+
104+
t.start();
105+
LOGGER.fine("Ping thread started for " + channel + " with a " + interval + " minute interval");
106+
}
107+
}

remoting/src/main/java/hudson/remoting/Engine.java

+1-16
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import java.util.List;
4040
import java.util.Collections;
4141
import java.util.logging.Logger;
42-
import static java.util.logging.Level.SEVERE;
4342

4443
/**
4544
* Slave agent engine that proactively connects to Hudson master.
@@ -234,27 +233,13 @@ public void run() {
234233
}
235234
}
236235

237-
final Socket socket = s;
238236
final Channel channel = new Channel("channel", executor,
239237
in,
240238
new BufferedOutputStream(s.getOutputStream()));
241-
PingThread t = new PingThread(channel) {
242-
protected void onDead() {
243-
try {
244-
if (!channel.isInClosed()) {
245-
LOGGER.info("Ping failed. Terminating the socket.");
246-
socket.close();
247-
}
248-
} catch (IOException e) {
249-
LOGGER.log(SEVERE, "Failed to terminate the socket", e);
250-
}
251-
}
252-
};
253-
t.start();
239+
254240
listener.status("Connected");
255241
channel.join();
256242
listener.status("Terminated");
257-
t.interrupt(); // make sure the ping thread is terminated
258243
listener.onDisconnect();
259244

260245
if(noReconnect)

0 commit comments

Comments
 (0)