Skip to content

Commit e0c3d8e

Browse files
authored
fix: Logging headers when retrying request (#1164)
1 parent ae32afb commit e0c3d8e

4 files changed

Lines changed: 52 additions & 3 deletions

File tree

src/main/java/com/box/sdk/BackoffCounter.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,20 @@ public int getAttemptsRemaining() {
2222
return this.attemptsRemaining;
2323
}
2424

25+
/**
26+
* Waits for some random amount of time {@link BackoffCounter#calculateDelay()}
27+
* @throws InterruptedException
28+
*/
2529
public void waitBackoff() throws InterruptedException {
2630
int delay = this.calculateDelay();
2731
this.waitBackoff(delay);
2832
}
2933

34+
/**
35+
* Waits for specified amount of miliseconds.
36+
* @param delay Time to wait for in miliseconds.
37+
* @throws InterruptedException
38+
*/
3039
public void waitBackoff(int delay) throws InterruptedException {
3140
if (LOGGER.isWarnEnabled()) {
3241
LOGGER.warn(String.format(
@@ -50,12 +59,16 @@ public void reset(int maxAttempts) {
5059
this.attemptsRemaining = maxAttempts;
5160
}
5261

62+
/**
63+
* Generates some random amount of time to backoff.
64+
* Time is within <16000, 48000) ms
65+
* @return Time in miliseconds.
66+
*/
5367
private int calculateDelay() {
5468
int exponent = this.maxAttempts - this.attemptsRemaining;
5569
double minWindow = 1 - RANDOM_FACTOR;
5670
double maxWindow = 1 + RANDOM_FACTOR;
5771
double jitter = (Math.random() * (maxWindow - minWindow)) + minWindow;
58-
5972
return (int) (Math.pow(2, exponent) * BASE_TIMEOUT * jitter);
6073
}
6174
}

src/main/java/com/box/sdk/BoxAPIRequest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.box.sdk;
22

3+
import static com.box.sdk.internal.utils.CollectionUtils.mapToString;
34
import static java.lang.String.format;
45

56
import com.box.sdk.http.ContentType;
@@ -389,9 +390,10 @@ public BoxAPIResponse send(ProgressListener listener) {
389390
}
390391

391392
LOGGER.warn(
392-
format("Retrying request due to transient error status=%d body=%s",
393+
format("Retrying request due to transient error status=%d body=%s headers=%s",
393394
apiException.getResponseCode(),
394-
apiException.getResponse())
395+
apiException.getResponse(),
396+
mapToString(apiException.getHeaders()))
395397
);
396398

397399
try {

src/main/java/com/box/sdk/internal/utils/CollectionUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.util.Collection;
55
import java.util.LinkedList;
66
import java.util.List;
7+
import java.util.Map;
8+
import java.util.stream.Collectors;
79

810
/**
911
* {@link Collection} related utlities.
@@ -49,6 +51,12 @@ public static <T> List<T> createListFrom(Iterable<T> iterable) {
4951
return result;
5052
}
5153

54+
public static String mapToString(Map<?, ?> map) {
55+
return map.keySet().stream()
56+
.map(k -> k + "=" + map.get(k))
57+
.collect(Collectors.joining(",\n", "{\n", "\n}"));
58+
}
59+
5260
/**
5361
* Contract for {@link Collection}-s mapping.
5462
*

src/test/java/com/box/sdk/BoxAPIRequestTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.junit.Assert.assertEquals;
1919
import static org.junit.Assert.assertNotNull;
2020
import static org.junit.Assert.fail;
21+
import static org.mockito.ArgumentMatchers.eq;
2122
import static org.mockito.Mockito.mock;
2223

2324
import com.eclipsesource.json.ParseException;
@@ -30,6 +31,7 @@
3031
import java.util.zip.GZIPOutputStream;
3132
import org.junit.Rule;
3233
import org.junit.Test;
34+
import org.mockito.Mockito;
3335

3436
public class BoxAPIRequestTest {
3537
@Rule
@@ -110,6 +112,30 @@ public void requestRetriesTheNumberOfTimesConfiguredInTheAPIConnection() {
110112
}
111113
}
112114

115+
@Test
116+
public void requestRetriesUsingSecondsProvidedInRetryHeader() throws InterruptedException {
117+
final int expectedNumRetryAttempts = 1;
118+
stubFor(get(urlEqualTo("/")).willReturn(aResponse()
119+
.withStatus(429)
120+
.withBody("{}")
121+
.withHeader("Retry-After", "20")
122+
));
123+
Time mockTime = mock(Time.class);
124+
BackoffCounter backoffCounter = new BackoffCounter(mockTime);
125+
126+
BoxAPIConnection api = createConnectionWith(boxMockUrl().toString());
127+
api.setMaxRetryAttempts(expectedNumRetryAttempts);
128+
129+
BoxAPIRequest request = new BoxAPIRequest(api, boxMockUrl(), "GET");
130+
request.setBackoffCounter(backoffCounter);
131+
132+
try {
133+
request.send();
134+
} catch (BoxAPIException e) {
135+
Mockito.verify(mockTime).waitDuration(eq(20000));
136+
}
137+
}
138+
113139
@Test
114140
public void requestSendsXBoxUAHeader() {
115141

0 commit comments

Comments
 (0)