process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
HttpRequest httpRequest = context.httpRequest();
boolean considerSecondary = (httpRequest.httpMethod().equals(HttpMethod.GET)
- || httpRequest.httpMethod().equals(HttpMethod.HEAD))
- && (this.requestRetryOptions.secondaryHost() != null);
+ || httpRequest.httpMethod().equals(HttpMethod.HEAD))
+ && (this.requestRetryOptions.secondaryHost() != null);
return this.attemptAsync(httpRequest, next, 1, considerSecondary, 1);
}
/**
- * This method actually attempts to send the request and determines if we should attempt again and, if so, how
- * long to wait before sending out the next request.
+ * This method actually attempts to send the request and determines if we should attempt again and, if so, how long
+ * to wait before sending out the next request.
*
- * Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) When to retry: connection failure
- * or an HTTP status code of 500 or greater, except 501 and 505 If using a secondary: Odd tries go against
- * primary; even tries go against the secondary For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8,
- * 1.2) If secondary gets a 404, don't fail, retry but future retries are only against the primary When retrying
- * against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2))
+ * Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) When to retry: connection failure or
+ * an HTTP status code of 500 or greater, except 501 and 505 If using a secondary: Odd tries go against primary;
+ * even tries go against the secondary For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, 1.2) If
+ * secondary gets a 404, don't fail, retry but future retries are only against the primary When retrying against a
+ * secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2))
*
- * @param httpRequest
- * The request to try.
- * @param primaryTry
- * This indicates how man tries we've attempted against the primary DC.
- * @param considerSecondary
- * Before each try, we'll select either the primary or secondary URL if appropriate.
- * @param attempt
- * This indicates the total number of attempts to send the request.
- *
- * @return A single containing either the successful response or an error that was not retryable because either
- * the maxTries was exceeded or retries will not mitigate the issue.
+ * @param httpRequest The request to try.
+ * @param primaryTry This indicates how man tries we've attempted against the primary DC.
+ * @param considerSecondary Before each try, we'll select either the primary or secondary URL if appropriate.
+ * @param attempt This indicates the total number of attempts to send the request.
+ * @return A single containing either the successful response or an error that was not retryable because either the
+ * maxTries was exceeded or retries will not mitigate the issue.
*/
private Mono attemptAsync(final HttpRequest httpRequest, HttpPipelineNextPolicy next, final int primaryTry,
- final boolean considerSecondary,
- final int attempt) {
+ final boolean considerSecondary,
+ final int attempt) {
// Determine which endpoint to try. It's primary if there is no secondary or if it is an odd number attempt.
final boolean tryingPrimary = !considerSecondary || (attempt % 2 != 0);
@@ -97,7 +92,7 @@ stream, the buffers that were emitted will have already been consumed (their pos
duplicates the ByteBuffer object, not the underlying data.
*/
Flux bufferedBody = httpRequest.body() == null
- ? null : httpRequest.body().map(ByteBuf::duplicate);
+ ? null : httpRequest.body().map(ByteBuf::duplicate);
httpRequest.body(bufferedBody);
if (!tryingPrimary) {
UrlBuilder builder = UrlBuilder.parse(httpRequest.url());
@@ -114,55 +109,55 @@ stream, the buffers that were emitted will have already been consumed (their pos
until after the retry backoff delay, so we call delaySubscription.
*/
return next.clone().process()
- .timeout(Duration.ofSeconds(this.requestRetryOptions.tryTimeout()))
- .delaySubscription(Duration.ofMillis(delayMs))
- .flatMap(response -> {
- boolean newConsiderSecondary = considerSecondary;
- String action;
- int statusCode = response.statusCode();
+ .timeout(Duration.ofSeconds(this.requestRetryOptions.tryTimeout()))
+ .delaySubscription(Duration.ofMillis(delayMs))
+ .flatMap(response -> {
+ boolean newConsiderSecondary = considerSecondary;
+ String action;
+ int statusCode = response.statusCode();
/*
If attempt was against the secondary & it returned a StatusNotFound (404), then the
resource was not found. This may be due to replication delay. So, in this case,
we'll never try the secondary again for this operation.
*/
- if (!tryingPrimary && statusCode == 404) {
- newConsiderSecondary = false;
- action = "Retry: Secondary URL returned 404";
- } else if (statusCode == 503 || statusCode == 500) {
- action = "Retry: Temporary error or server timeout";
- } else {
- action = "NoRetry: Successful HTTP request";
- }
-
- if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) {
+ if (!tryingPrimary && statusCode == 404) {
+ newConsiderSecondary = false;
+ action = "Retry: Secondary URL returned 404";
+ } else if (statusCode == 503 || statusCode == 500) {
+ action = "Retry: Temporary error or server timeout";
+ } else {
+ action = "NoRetry: Successful HTTP request";
+ }
+
+ if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) {
/*
We increment primaryTry if we are about to try the primary again (which is when we
consider the secondary and tried the secondary this time (tryingPrimary==false) or
we do not consider the secondary at all (considerSecondary==false)). This will
ensure primaryTry is correct when passed to calculate the delay.
*/
- int newPrimaryTry = !tryingPrimary || !considerSecondary
- ? primaryTry + 1 : primaryTry;
- return attemptAsync(httpRequest, next, newPrimaryTry, newConsiderSecondary,
- attempt + 1);
- }
- return Mono.just(response);
- })
- .onErrorResume(throwable -> {
+ int newPrimaryTry = !tryingPrimary || !considerSecondary
+ ? primaryTry + 1 : primaryTry;
+ return attemptAsync(httpRequest, next, newPrimaryTry, newConsiderSecondary,
+ attempt + 1);
+ }
+ return Mono.just(response);
+ })
+ .onErrorResume(throwable -> {
/*
It is likely that many users will not realize that their Flux must be replayable and
get an error upon retries when the provided data length does not match the length of the exact
data. We cannot enforce the desired Flux behavior, so we provide a hint when this is likely
the root cause.
*/
- if (throwable instanceof IllegalStateException && attempt > 1) {
- return Mono.error(new IllegalStateException("The request failed because the "
- + "size of the contents of the provided Flux did not match the provided "
- + "data size upon attempting to retry. This is likely caused by the Flux "
- + "not being replayable. To support retries, all Fluxes must produce the "
- + "same data for each subscriber. Please ensure this behavior.", throwable));
- }
+ if (throwable instanceof IllegalStateException && attempt > 1) {
+ return Mono.error(new IllegalStateException("The request failed because the "
+ + "size of the contents of the provided Flux did not match the provided "
+ + "data size upon attempting to retry. This is likely caused by the Flux "
+ + "not being replayable. To support retries, all Fluxes must produce the "
+ + "same data for each subscriber. Please ensure this behavior.", throwable));
+ }
/*
IOException is a catch-all for IO related errors. Technically it includes many types which may
@@ -170,28 +165,28 @@ we do not consider the secondary at all (considerSecondary==false)). This will
either case, it is better to optimistically retry instead of failing too soon.
A Timeout Exception is a client-side timeout coming from Rx.
*/
- String action;
- if (throwable instanceof IOException) {
- action = "Retry: Network error";
- } else if (throwable instanceof TimeoutException) {
- action = "Retry: Client timeout";
- } else {
- action = "NoRetry: Unknown error";
- }
-
- if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) {
+ String action;
+ if (throwable instanceof IOException) {
+ action = "Retry: Network error";
+ } else if (throwable instanceof TimeoutException) {
+ action = "Retry: Client timeout";
+ } else {
+ action = "NoRetry: Unknown error";
+ }
+
+ if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) {
/*
We increment primaryTry if we are about to try the primary again (which is when we
consider the secondary and tried the secondary this time (tryingPrimary==false) or
we do not consider the secondary at all (considerSecondary==false)). This will
ensure primaryTry is correct when passed to calculate the delay.
*/
- int newPrimaryTry = !tryingPrimary || !considerSecondary
- ? primaryTry + 1 : primaryTry;
- return attemptAsync(httpRequest, next, newPrimaryTry, considerSecondary,
- attempt + 1);
- }
- return Mono.error(throwable);
- });
+ int newPrimaryTry = !tryingPrimary || !considerSecondary
+ ? primaryTry + 1 : primaryTry;
+ return attemptAsync(httpRequest, next, newPrimaryTry, considerSecondary,
+ attempt + 1);
+ }
+ return Mono.error(throwable);
+ });
}
}
diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java b/storage/client/common/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java
similarity index 100%
rename from storage/client/blob/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java
rename to storage/client/common/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java
diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java b/storage/client/common/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java
similarity index 99%
rename from storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java
rename to storage/client/common/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java
index ba2debfcd3620..4af3edf7f229b 100644
--- a/storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java
+++ b/storage/client/common/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java
@@ -22,6 +22,7 @@ public final class SASTokenCredentialPolicy implements HttpPipelinePolicy {
/**
* Creates a SAS token credential policy that appends the SAS token to the request URL's query.
+ *
* @param credential SAS token credential
*/
public SASTokenCredentialPolicy(SASTokenCredential credential) {
diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/common/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java
similarity index 100%
rename from storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java
rename to storage/client/common/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java
diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/package-info.java b/storage/client/common/src/main/java/com/azure/storage/common/policy/package-info.java
similarity index 100%
rename from storage/client/blob/src/main/java/com/azure/storage/common/policy/package-info.java
rename to storage/client/common/src/main/java/com/azure/storage/common/policy/package-info.java
diff --git a/storage/client/file/pom.xml b/storage/client/file/pom.xml
index 5355d42110408..30f886983ae4d 100644
--- a/storage/client/file/pom.xml
+++ b/storage/client/file/pom.xml
@@ -37,6 +37,11 @@
azure-core
1.0.0-preview.2
+
+ com.azure
+ azure-storage-common
+ 12.0.0-preview.2
+