JCLOUDS-1005: Retry on 500 and 503 errors

This requires rewriting the URL for b2_upload_file and b2_upload_part
requests.
This commit is contained in:
Andrew Gaul 2016-06-14 21:35:19 -07:00
parent f66e0a3fcc
commit 2ff68fc79e
3 changed files with 99 additions and 0 deletions

View File

@ -48,6 +48,8 @@ public final class B2ApiMetadata extends BaseHttpApiMetadata {
public static Properties defaultProperties() { public static Properties defaultProperties() {
Properties properties = BaseHttpApiMetadata.defaultProperties(); Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(Constants.PROPERTY_SESSION_INTERVAL, String.valueOf(TimeUnit.HOURS.toSeconds(1))); properties.setProperty(Constants.PROPERTY_SESSION_INTERVAL, String.valueOf(TimeUnit.HOURS.toSeconds(1)));
properties.setProperty(Constants.PROPERTY_IDEMPOTENT_METHODS, "DELETE,GET,HEAD,OPTIONS,POST,PUT");
properties.setProperty(Constants.PROPERTY_RETRY_DELAY_START, String.valueOf(TimeUnit.SECONDS.toMillis(1)));
return properties; return properties;
} }

View File

@ -26,9 +26,11 @@ import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.b2.B2Api; import org.jclouds.b2.B2Api;
import org.jclouds.b2.domain.Authorization; import org.jclouds.b2.domain.Authorization;
import org.jclouds.b2.filters.B2RetryHandler;
import org.jclouds.b2.filters.RequestAuthorization; import org.jclouds.b2.filters.RequestAuthorization;
import org.jclouds.b2.handlers.ParseB2ErrorFromJsonContent; import org.jclouds.b2.handlers.ParseB2ErrorFromJsonContent;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError; import org.jclouds.http.annotation.ServerError;
@ -57,6 +59,11 @@ public final class B2HttpApiModule extends HttpApiModule<B2Api> {
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseB2ErrorFromJsonContent.class); bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseB2ErrorFromJsonContent.class);
} }
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ServerError.class).to(B2RetryHandler.class);
}
@Provides @Provides
@Singleton @Singleton
static Supplier<Authorization> provideAuthorizationSupplier(final B2Api b2Api) { static Supplier<Authorization> provideAuthorizationSupplier(final B2Api b2Api) {

View File

@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.b2.filters;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import static org.jclouds.http.HttpUtils.releasePayload;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.b2.B2Api;
import org.jclouds.b2.domain.GetUploadPartResponse;
import org.jclouds.b2.domain.UploadUrlResponse;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.Logger;
import com.google.common.net.HttpHeaders;
import com.google.inject.Singleton;
@Singleton
public final class B2RetryHandler extends BackoffLimitedRetryHandler implements HttpRequestFilter {
private final B2Api api;
@Resource
private Logger logger = Logger.NULL;
@Inject
B2RetryHandler(B2Api api) {
this.api = api;
}
@Override
public HttpRequest filter(HttpRequest request) throws HttpException {
HttpRequest.Builder<?> builder = request.toBuilder();
// B2 requires retrying on a different storage node for uploads
String path = request.getEndpoint().getPath();
if (path.startsWith("/b2api/v1/b2_upload_file")) {
String bucketId = path.split("/")[4];
UploadUrlResponse uploadUrl = api.getObjectApi().getUploadUrl(bucketId);
builder.endpoint(uploadUrl.uploadUrl())
.replaceHeader(HttpHeaders.AUTHORIZATION, uploadUrl.authorizationToken());
} else if (path.startsWith("/b2api/v1/b2_upload_part")) {
String fileId = path.split("/")[4];
GetUploadPartResponse uploadUrl = api.getMultipartApi().getUploadPartUrl(fileId);
builder.endpoint(uploadUrl.uploadUrl())
.replaceHeader(HttpHeaders.AUTHORIZATION, uploadUrl.authorizationToken());
}
return builder.build();
}
@Override
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
boolean retry = false;
try {
byte[] data = closeClientButKeepContentStream(response);
switch (response.getStatusCode()) {
case 500:
case 503:
retry = super.shouldRetryRequest(command, response);
break;
default:
break;
}
} finally {
releasePayload(response);
}
return retry;
}
}