Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
* A collection of headers on an HTTP request or response.
*/
public class HttpHeaders implements Iterable<HttpHeader> {

/**
* The header which will have retry after value in milliseconds.
*/
public static final String AZURE_RETRY_AFTER_MS_HEADER = "retry-after-ms";
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated

/**
* The header which will have retry after value in milliseconds.
*/
public static final String AZURE_X_MS_RETRY_AFTER_MS_HEADER = "x-ms-retry-after-ms";
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated

Comment thread
hemanttanwar marked this conversation as resolved.
Outdated
private final Map<String, HttpHeader> headers = new ConcurrentHashMap<>();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

import static com.azure.core.util.CoreUtils.isNullOrEmpty;

import java.time.temporal.ChronoUnit;

import java.util.Objects;

import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
import com.azure.core.http.HttpRequest;
import com.azure.core.http.HttpResponse;
import java.util.Objects;

import com.azure.core.util.logging.ClientLogger;

import reactor.core.publisher.Mono;

import java.time.Duration;
Expand All @@ -20,25 +25,58 @@
*/
public class RetryPolicy implements HttpPipelinePolicy {

private static final String RETRY_AFTER_MS_HEADER = "retry-after-ms";
Comment thread
hemanttanwar marked this conversation as resolved.

private final ClientLogger logger = new ClientLogger(RetryPolicy.class);
private final RetryStrategy retryStrategy;

private final String retryAfterHeader;
private final ChronoUnit retryAfterTimeUnit;

/**
* Creates a default {@link ExponentialBackoff} retry policy.
*/
public RetryPolicy() {
this(new ExponentialBackoff());
this(new ExponentialBackoff(), null, null);
}

/**
* Creates a default {@link ExponentialBackoff} retry policy.
* @param retryAfterHeader The retry after http header name to be used get retry after value from
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated
* @param retryAfterTimeUnit The time unit to use while applying retry based on value specified in
* * {@code retryAfterHeader} in {@link HttpResponse}.
* {@link HttpResponse}.
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated
*/
public RetryPolicy(String retryAfterHeader, ChronoUnit retryAfterTimeUnit) {
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated
this(new ExponentialBackoff(), retryAfterHeader, retryAfterTimeUnit);
}

/**
* Creates a RetryPolicy with the provided {@link RetryStrategy}.
*
* @param retryStrategy The {@link RetryStrategy} used for retries.
* @throws NullPointerException if {@code retryStrategy} is {@code null}.
*/
public RetryPolicy(RetryStrategy retryStrategy) {
this.retryStrategy = Objects.requireNonNull(retryStrategy, "'retryStrategy' cannot be null");
this(retryStrategy, null, null);
}

/**
* Creates a {@link RetryPolicy} with the provided {@link RetryStrategy} and {@code retryAfterHeader}.
*
* @param retryStrategy The {@link RetryStrategy} used for retries.
* @param retryAfterHeader The retry after http header name to be used get retry after value from
* {@link HttpResponse}. The value {@code null} is valid.
* @param retryAfterTimeUnit The time unit to use while applying retry based on value specified in
* {@code retryAfterHeader} in {@link HttpResponse}.The value {@code null} is valid only in case when
* {@code retryAfterHeader} is empty or {@code null}.
* @throws NullPointerException if {@code retryStrategy} is {@code null}.
Comment thread
hemanttanwar marked this conversation as resolved.
Outdated
*/
public RetryPolicy(RetryStrategy retryStrategy, String retryAfterHeader, ChronoUnit retryAfterTimeUnit) {
Comment thread
alzimmermsft marked this conversation as resolved.
Outdated
this.retryStrategy = Objects.requireNonNull(retryStrategy, "'retryStrategy' cannot be null.");
this.retryAfterHeader = retryAfterHeader;
this.retryAfterTimeUnit = retryAfterTimeUnit;
if (!isNullOrEmpty(retryAfterHeader)) {
Objects.requireNonNull(retryAfterTimeUnit, "'retryAfterTimeUnit' cannot be null.");
}

@hemanttanwar hemanttanwar Nov 7, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retryAfterHeader : This could be null when user do not want to use any response header for retry. This is change of behavior from GA release, In GA we check for value of header 'retry-after-ms' by default. This is discussed with Srikanta

}

@Override
Expand Down Expand Up @@ -94,14 +132,18 @@ private Duration determineDelayDuration(HttpResponse response, int tryCount) {
return retryStrategy.calculateRetryDelay(tryCount);
}

String retryHeader = response.getHeaderValue(RETRY_AFTER_MS_HEADER);
String retryHeaderValue = null;

if (!isNullOrEmpty(retryAfterHeader)) {
retryHeaderValue = response.getHeaderValue(retryAfterHeader);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retryAfterHeader : This could be null when user do not want to use any response header for retry.

}

// Retry header is missing or empty, return the default delay duration.
if (isNullOrEmpty(retryHeader)) {
if (isNullOrEmpty(retryHeaderValue)) {
return retryStrategy.calculateRetryDelay(tryCount);
}

// Use the response delay duration, the server returned it for a reason.
return Duration.ofMillis(Integer.parseInt(retryHeader));
return Duration.of(Integer.parseInt(retryHeaderValue), retryAfterTimeUnit);
}
}