2020
2121import com .google .common .annotations .VisibleForTesting ;
2222import com .google .common .io .BaseEncoding ;
23+ import com .google .common .io .ByteStreams ;
2324import com .google .gson .JsonElement ;
2425import com .google .gson .JsonObject ;
2526import com .google .gson .JsonParser ;
4546 * parses it to extract its expiration time, and caches/refreshes it.
4647 */
4748public final class JwtTokenFileCallCredentials extends CallCredentials {
49+ private static final int MAX_FILE_SIZE_BYTES = 1048576 ;
4850
4951 private static final Logger log = Logger .getLogger (JwtTokenFileCallCredentials .class .getName ());
5052
5153 private static final Metadata .Key <String > AUTHORIZATION_HEADER =
5254 Metadata .Key .of ("authorization" , Metadata .ASCII_STRING_MARSHALLER );
5355
54- private static final long INITIAL_BACKOFF_MS = 1000 ;
55- private static final long MAX_BACKOFF_MS = 60000 ;
56- private static final double BACKOFF_MULTIPLIER = 2.0 ;
56+ private static final long INITIAL_BACKOFF_MILLIS = 1000 ;
57+ private static final long MAX_BACKOFF_MILLIS = 120000 ;
58+ private static final double BACKOFF_MULTIPLIER = 1.6 ;
59+ private static final double JITTER = 0.2 ;
5760
5861 private final String filePath ;
5962 private final TimeProvider timeProvider ;
@@ -69,7 +72,7 @@ private enum ReadState {
6972 private long expirationTimeMillis ;
7073 private ReadState readState = ReadState .IDLE ;
7174 private Status lastReadFailureStatus ;
72- private long currentBackoffMs ;
75+ private long currentBackoffMillis ;
7376 private long nextAttemptTimeMillis ;
7477 private final List <MetadataApplier > queuedAppliers = new ArrayList <>();
7578
@@ -122,11 +125,17 @@ public void applyRequestMetadata(
122125
123126 if (hasValidCache ) {
124127 tokenToApply = new TokenInfo (cachedToken , expirationTimeMillis );
128+ if (readState == ReadState .BACKOFF && now >= nextAttemptTimeMillis ) {
129+ readState = ReadState .IDLE ;
130+ }
125131 if (expiringSoon && readState == ReadState .IDLE ) {
126132 readState = ReadState .READING ;
127133 triggerRead = true ;
128134 }
129135 } else {
136+ if (readState == ReadState .BACKOFF && now >= nextAttemptTimeMillis ) {
137+ readState = ReadState .IDLE ;
138+ }
130139 if (readState == ReadState .BACKOFF ) {
131140 failStatus = lastReadFailureStatus != null ? lastReadFailureStatus : Status .UNAVAILABLE ;
132141 } else {
@@ -214,7 +223,7 @@ private void loadToken() {
214223 expirationTimeMillis = tokenInfo .expirationTimeMillis ;
215224 readState = ReadState .IDLE ;
216225 lastReadFailureStatus = null ;
217- currentBackoffMs = 0 ;
226+ currentBackoffMillis = 0 ;
218227 nextAttemptTimeMillis = 0 ;
219228
220229 appliersToApply .addAll (queuedAppliers );
@@ -223,13 +232,16 @@ private void loadToken() {
223232 lastReadFailureStatus = status ;
224233 readState = ReadState .BACKOFF ;
225234
226- if (currentBackoffMs == 0 ) {
227- currentBackoffMs = INITIAL_BACKOFF_MS ;
235+ if (currentBackoffMillis == 0 ) {
236+ currentBackoffMillis = INITIAL_BACKOFF_MILLIS ;
228237 } else {
229- currentBackoffMs = Math .min (
230- (long ) (currentBackoffMs * BACKOFF_MULTIPLIER ), MAX_BACKOFF_MS );
238+ currentBackoffMillis = Math .min (
239+ (long ) (currentBackoffMillis * BACKOFF_MULTIPLIER ), MAX_BACKOFF_MILLIS );
231240 }
232- nextAttemptTimeMillis = timeProvider .currentTimeMillis () + currentBackoffMs ;
241+ double uniformRandom = Math .random () * 2 - 1 ;
242+ long jitteredBackoff = (long ) (currentBackoffMillis
243+ + uniformRandom * JITTER * currentBackoffMillis );
244+ nextAttemptTimeMillis = timeProvider .currentTimeMillis () + jitteredBackoff ;
233245
234246 appliersToFail .addAll (queuedAppliers );
235247 queuedAppliers .clear ();
@@ -261,15 +273,15 @@ private void loadToken() {
261273 private TokenInfo readAndParseTokenFile () throws IOException {
262274 File file = new File (filePath );
263275 long length = file .length ();
264- if (length > 1048576 ) {
276+ if (length > MAX_FILE_SIZE_BYTES ) {
265277 throw new IOException ("File size exceeds 1 MB limit: " + length );
266278 }
267279 byte [] bytes ;
268280 try (InputStream in = new FileInputStream (file )) {
269- bytes = com . google . common . io . ByteStreams .toByteArray (
270- com . google . common . io . ByteStreams .limit (in , 1048577 ));
281+ bytes = ByteStreams .toByteArray (
282+ ByteStreams .limit (in , MAX_FILE_SIZE_BYTES + 1 ));
271283 }
272- if (bytes .length > 1048576 ) {
284+ if (bytes .length > MAX_FILE_SIZE_BYTES ) {
273285 throw new IOException ("File size exceeds 1 MB limit: " + bytes .length );
274286 }
275287 String token = new String (bytes , StandardCharsets .UTF_8 ).trim ();
0 commit comments