50
50
import java .security .cert .CertificateException ;
51
51
import java .security .cert .X509Certificate ;
52
52
import java .security .interfaces .RSAPublicKey ;
53
+ import java .time .Duration ;
53
54
import java .util .ArrayList ;
54
55
import java .util .Arrays ;
55
56
import java .util .HashMap ;
93
94
import org .jenkinsci .remoting .protocol .cert .PublicKeyMatchingX509ExtendedTrustManager ;
94
95
import org .jenkinsci .remoting .protocol .impl .ConnectionRefusalException ;
95
96
import org .jenkinsci .remoting .util .KeyUtils ;
97
+ import org .jenkinsci .remoting .util .RetryUtils ;
96
98
import org .jenkinsci .remoting .util .VersionNumber ;
99
+ import org .kohsuke .accmod .Restricted ;
100
+ import org .kohsuke .accmod .restrictions .NoExternalUse ;
97
101
98
102
/**
99
103
* Agent engine that proactively connects to Jenkins controller.
@@ -178,6 +182,12 @@ public Thread newThread(@NonNull final Runnable r) {
178
182
179
183
private boolean noReconnect = false ;
180
184
185
+ private int delay = 10 ;
186
+
187
+ private double jitterFactor = 0 ;
188
+
189
+ private int jitter = 0 ;
190
+
181
191
/**
182
192
* Determines whether the socket will have {@link Socket#setKeepAlive(boolean)} set or not.
183
193
*
@@ -397,6 +407,21 @@ public void setNoReconnect(boolean noReconnect) {
397
407
this .noReconnect = noReconnect ;
398
408
}
399
409
410
+ @ Restricted (NoExternalUse .class )
411
+ public void setDelay (int delay ) {
412
+ this .delay = delay ;
413
+ }
414
+
415
+ @ Restricted (NoExternalUse .class )
416
+ public void setJitterFactor (double jitterFactor ) {
417
+ this .jitterFactor = jitterFactor ;
418
+ }
419
+
420
+ @ Restricted (NoExternalUse .class )
421
+ public void setJitter (int jitter ) {
422
+ this .jitter = jitter ;
423
+ }
424
+
400
425
/**
401
426
* Determines if JNLPAgentEndpointResolver will not perform certificate validation in the HTTPs mode.
402
427
*
@@ -694,8 +719,8 @@ public void closeRead() throws IOException {
694
719
}
695
720
events .onDisconnect ();
696
721
while (true ) {
697
- // TODO refactor various sleep statements into a common method
698
- TimeUnit . SECONDS . sleep (10 );
722
+ Duration duration = RetryUtils . getDuration ( delay , jitterFactor , jitter );
723
+ Thread . sleep (duration . toMillis () );
699
724
// Unlike JnlpAgentEndpointResolver, we do not use $jenkins/tcpSlaveAgentListener/, as that will be a 404 if the TCP port is disabled.
700
725
URL ping = new URL (hudsonUrl , "login" );
701
726
try {
@@ -761,9 +786,9 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) {
761
786
endpoint = resolver .resolve ();
762
787
} catch (IOException e ) {
763
788
if (!noReconnect ) {
764
- events . status ( "Could not locate server among " + candidateUrls + "; waiting 10 seconds before retry" , e );
765
- // TODO refactor various sleep statements into a common method
766
- TimeUnit . SECONDS . sleep (10 );
789
+ Duration duration = RetryUtils . getDuration ( delay , jitterFactor , jitter );
790
+ events . status ( "Could not locate server among " + candidateUrls + "; waiting " + RetryUtils . formatDuration ( duration ) + " seconds before retry" , e );
791
+ Thread . sleep (duration . toMillis () );
767
792
continue ;
768
793
} else {
769
794
if (Boolean .getBoolean (Engine .class .getName () + ".nonFatalJnlpAgentEndpointResolutionExceptions" )) {
@@ -881,26 +906,34 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) {
881
906
}
882
907
883
908
private JnlpEndpointResolver createEndpointResolver (List <String > jenkinsUrls ) {
884
- JnlpEndpointResolver resolver ;
885
909
if (directConnection == null ) {
886
910
SSLSocketFactory sslSocketFactory = null ;
887
911
try {
888
912
sslSocketFactory = getSSLSocketFactory ();
889
913
} catch (Exception e ) {
890
914
events .error (e );
891
915
}
892
- resolver = new JnlpAgentEndpointResolver (jenkinsUrls , credentials , proxyCredentials , tunnel ,
893
- sslSocketFactory , disableHttpsCertValidation );
916
+ JnlpAgentEndpointResolver jnlpAgentEndpointResolver =
917
+ new JnlpAgentEndpointResolver (
918
+ jenkinsUrls ,
919
+ credentials ,
920
+ proxyCredentials ,
921
+ tunnel ,
922
+ sslSocketFactory ,
923
+ disableHttpsCertValidation );
924
+ jnlpAgentEndpointResolver .setDelay (delay );
925
+ jnlpAgentEndpointResolver .setJitterFactor (jitterFactor );
926
+ jnlpAgentEndpointResolver .setJitter (jitter );
927
+ return jnlpAgentEndpointResolver ;
894
928
} else {
895
- resolver = new JnlpAgentEndpointConfigurator (directConnection , instanceIdentity , protocols );
929
+ return new JnlpAgentEndpointConfigurator (directConnection , instanceIdentity , protocols );
896
930
}
897
- return resolver ;
898
931
}
899
932
900
933
private void onConnectionRejected (String greeting ) throws InterruptedException {
901
- events . status ( "reconnect rejected, sleeping 10s: " , new Exception ( "The server rejected the connection: " + greeting ) );
902
- // TODO refactor various sleep statements into a common method
903
- TimeUnit . SECONDS . sleep (10 );
934
+ Duration duration = RetryUtils . getDuration ( delay , jitterFactor , jitter );
935
+ events . status ( "reconnect rejected, sleeping " + RetryUtils . formatDuration ( duration ) + "s: " , new Exception ( "The server rejected the connection: " + greeting ));
936
+ Thread . sleep (duration . toMillis () );
904
937
}
905
938
906
939
/**
@@ -922,8 +955,8 @@ private Socket connectTcp(@NonNull JnlpAgentEndpoint endpoint) throws IOExceptio
922
955
if (retry ++>10 ) {
923
956
throw e ;
924
957
}
925
- // TODO refactor various sleep statements into a common method
926
- TimeUnit . SECONDS . sleep (10 );
958
+ Duration duration = RetryUtils . getDuration ( delay , jitterFactor , jitter );
959
+ Thread . sleep (duration . toMillis () );
927
960
events .status (msg +" (retrying:" +retry +")" ,e );
928
961
}
929
962
}
0 commit comments