23
23
*/
24
24
package hudson .slaves ;
25
25
26
+ import com .google .common .annotations .VisibleForTesting ;
26
27
import hudson .Extension ;
27
28
import hudson .FilePath ;
28
29
import jenkins .util .SystemProperties ;
34
35
import jenkins .security .MasterToSlaveCallable ;
35
36
import jenkins .slaves .PingFailureAnalyzer ;
36
37
38
+ import javax .annotation .CheckForNull ;
37
39
import java .io .IOException ;
38
40
import java .util .concurrent .atomic .AtomicBoolean ;
39
41
import java .util .logging .Level ;
@@ -86,28 +88,42 @@ public ChannelPinger() {
86
88
87
89
@ Override
88
90
public void preOnline (Computer c , Channel channel , FilePath root , TaskListener listener ) {
89
- install (channel );
91
+ SlaveComputer slaveComputer = null ;
92
+ if (c instanceof SlaveComputer ) {
93
+ slaveComputer = (SlaveComputer ) c ;
94
+ }
95
+ install (channel , slaveComputer );
90
96
}
91
97
98
+ /**
99
+ * @deprecated Use {@link #install(Channel, SlaveComputer)} instead.
100
+ */
101
+ @ Deprecated
92
102
public void install (Channel channel ) {
103
+ install (channel , null );
104
+ }
105
+
106
+ @ VisibleForTesting
107
+ /*package*/ void install (Channel channel , @ CheckForNull SlaveComputer c ) {
93
108
if (pingTimeoutSeconds < 1 || pingIntervalSeconds < 1 ) {
94
109
LOGGER .warning ("Agent ping is disabled" );
95
110
return ;
96
111
}
97
112
113
+ // set up ping from both directions, so that in case of a router dropping a connection,
114
+ // both sides can notice it and take compensation actions.
98
115
try {
99
116
channel .call (new SetUpRemotePing (pingTimeoutSeconds , pingIntervalSeconds ));
100
117
LOGGER .fine ("Set up a remote ping for " + channel .getName ());
101
118
} catch (Exception e ) {
102
- LOGGER .severe ( "Failed to set up a ping for " + channel .getName ());
119
+ LOGGER .log ( Level . SEVERE , "Failed to set up a ping for " + channel .getName (), e );
103
120
}
104
121
105
- // set up ping from both directions, so that in case of a router dropping a connection,
106
- // both sides can notice it and take compensation actions.
107
- setUpPingForChannel (channel , pingTimeoutSeconds , pingIntervalSeconds , true );
122
+ setUpPingForChannel (channel , c , pingTimeoutSeconds , pingIntervalSeconds , true );
108
123
}
109
124
110
- static class SetUpRemotePing extends MasterToSlaveCallable <Void , IOException > {
125
+ @ VisibleForTesting
126
+ /*package*/ static class SetUpRemotePing extends MasterToSlaveCallable <Void , IOException > {
111
127
private static final long serialVersionUID = -2702219700841759872L ;
112
128
@ Deprecated
113
129
private transient int pingInterval ;
@@ -121,7 +137,7 @@ static class SetUpRemotePing extends MasterToSlaveCallable<Void, IOException> {
121
137
122
138
@ Override
123
139
public Void call () throws IOException {
124
- setUpPingForChannel (Channel .current (), pingTimeoutSeconds , pingIntervalSeconds , false );
140
+ setUpPingForChannel (Channel .current (), null , pingTimeoutSeconds , pingIntervalSeconds , false );
125
141
return null ;
126
142
}
127
143
@@ -163,30 +179,35 @@ protected Object readResolve() {
163
179
}
164
180
}
165
181
166
- static void setUpPingForChannel (final Channel channel , int timeoutSeconds , int intervalSeconds , final boolean analysis ) {
182
+ @ VisibleForTesting
183
+ /*package*/ static void setUpPingForChannel (final Channel channel , final SlaveComputer computer , int timeoutSeconds , int intervalSeconds , final boolean analysis ) {
167
184
LOGGER .log (Level .FINE , "setting up ping on {0} with a {1} seconds interval and {2} seconds timeout" , new Object [] {channel .getName (), intervalSeconds , timeoutSeconds });
168
185
final AtomicBoolean isInClosed = new AtomicBoolean (false );
169
186
final PingThread t = new PingThread (channel , timeoutSeconds * 1000L , intervalSeconds * 1000L ) {
170
187
@ Override
171
188
protected void onDead (Throwable cause ) {
172
- try {
173
189
if (analysis ) {
174
190
analyze (cause );
175
191
}
176
- if (isInClosed .get ()) {
192
+ boolean inClosed = isInClosed .get ();
193
+ // Disassociate computer channel before closing it
194
+ if (computer != null ) {
195
+ computer .disconnect (); // TODO specify cause
196
+ }
197
+ if (inClosed ) {
177
198
LOGGER .log (Level .FINE ,"Ping failed after the channel " +channel .getName ()+" is already partially closed." ,cause );
178
199
} else {
179
200
LOGGER .log (Level .INFO ,"Ping failed. Terminating the channel " +channel .getName ()+"." ,cause );
180
- channel .close (cause );
181
201
}
182
- } catch (IOException e ) {
183
- LOGGER .log (Level .SEVERE ,"Failed to terminate the channel " +channel .getName (),e );
184
- }
185
202
}
186
203
/** Keep in a separate method so we do not even try to do class loading on {@link PingFailureAnalyzer} from an agent JVM. */
187
- private void analyze (Throwable cause ) throws IOException {
204
+ private void analyze (Throwable cause ) {
188
205
for (PingFailureAnalyzer pfa : PingFailureAnalyzer .all ()) {
189
- pfa .onPingFailure (channel ,cause );
206
+ try {
207
+ pfa .onPingFailure (channel , cause );
208
+ } catch (IOException ex ) {
209
+ LOGGER .log (Level .WARNING , "Ping failure analyzer failed for " + channel .getName (), ex );
210
+ }
190
211
}
191
212
}
192
213
@ Deprecated
0 commit comments