Create new handlers for every new request in GoogleCloudStorageService (#27339)
This commit changes the DefaultHttpRequestInitializer in order to make it create new HttpIOExceptionHandler and HttpUnsuccessfulResponseHandler for every new HTTP request instead of reusing the same two handlers for all requests. Closes #27092
This commit is contained in:
parent
1caa5c8e32
commit
dd51c231ac
|
@ -23,7 +23,6 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||||
import com.google.api.client.http.HttpBackOffIOExceptionHandler;
|
import com.google.api.client.http.HttpBackOffIOExceptionHandler;
|
||||||
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
|
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
|
||||||
import com.google.api.client.http.HttpIOExceptionHandler;
|
|
||||||
import com.google.api.client.http.HttpRequest;
|
import com.google.api.client.http.HttpRequest;
|
||||||
import com.google.api.client.http.HttpRequestInitializer;
|
import com.google.api.client.http.HttpRequestInitializer;
|
||||||
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
|
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
|
||||||
|
@ -34,9 +33,7 @@ import com.google.api.services.storage.Storage;
|
||||||
import com.google.api.services.storage.StorageScopes;
|
import com.google.api.services.storage.StorageScopes;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.settings.SecureSetting;
|
import org.elasticsearch.common.settings.SecureSetting;
|
||||||
import org.elasticsearch.common.settings.SecureString;
|
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
@ -46,8 +43,6 @@ import org.elasticsearch.env.Environment;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -76,16 +71,11 @@ interface GoogleCloudStorageService {
|
||||||
*/
|
*/
|
||||||
class InternalGoogleCloudStorageService extends AbstractComponent implements GoogleCloudStorageService {
|
class InternalGoogleCloudStorageService extends AbstractComponent implements GoogleCloudStorageService {
|
||||||
|
|
||||||
private static final String DEFAULT = "_default_";
|
|
||||||
|
|
||||||
private final Environment environment;
|
|
||||||
|
|
||||||
/** Credentials identified by client name. */
|
/** Credentials identified by client name. */
|
||||||
private final Map<String, GoogleCredential> credentials;
|
private final Map<String, GoogleCredential> credentials;
|
||||||
|
|
||||||
InternalGoogleCloudStorageService(Environment environment, Map<String, GoogleCredential> credentials) {
|
InternalGoogleCloudStorageService(Environment environment, Map<String, GoogleCredential> credentials) {
|
||||||
super(environment.settings());
|
super(environment.settings());
|
||||||
this.environment = environment;
|
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,15 +121,11 @@ interface GoogleCloudStorageService {
|
||||||
private final TimeValue connectTimeout;
|
private final TimeValue connectTimeout;
|
||||||
private final TimeValue readTimeout;
|
private final TimeValue readTimeout;
|
||||||
private final GoogleCredential credential;
|
private final GoogleCredential credential;
|
||||||
private final HttpUnsuccessfulResponseHandler handler;
|
|
||||||
private final HttpIOExceptionHandler ioHandler;
|
|
||||||
|
|
||||||
DefaultHttpRequestInitializer(GoogleCredential credential, TimeValue connectTimeout, TimeValue readTimeout) {
|
DefaultHttpRequestInitializer(GoogleCredential credential, TimeValue connectTimeout, TimeValue readTimeout) {
|
||||||
this.credential = credential;
|
this.credential = credential;
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
this.readTimeout = readTimeout;
|
this.readTimeout = readTimeout;
|
||||||
this.handler = new HttpBackOffUnsuccessfulResponseHandler(newBackOff());
|
|
||||||
this.ioHandler = new HttpBackOffIOExceptionHandler(newBackOff());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,13 +137,14 @@ interface GoogleCloudStorageService {
|
||||||
request.setReadTimeout((int) readTimeout.millis());
|
request.setReadTimeout((int) readTimeout.millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
request.setIOExceptionHandler(ioHandler);
|
request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(newBackOff()));
|
||||||
request.setInterceptor(credential);
|
request.setInterceptor(credential);
|
||||||
|
|
||||||
|
final HttpUnsuccessfulResponseHandler handler = new HttpBackOffUnsuccessfulResponseHandler(newBackOff());
|
||||||
request.setUnsuccessfulResponseHandler((req, resp, supportsRetry) -> {
|
request.setUnsuccessfulResponseHandler((req, resp, supportsRetry) -> {
|
||||||
// Let the credential handle the response. If it failed, we rely on our backoff handler
|
// Let the credential handle the response. If it failed, we rely on our backoff handler
|
||||||
return credential.handleResponse(req, resp, supportsRetry) || handler.handleResponse(req, resp, supportsRetry);
|
return credential.handleResponse(req, resp, supportsRetry) || handler.handleResponse(req, resp, supportsRetry);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,17 +19,35 @@
|
||||||
|
|
||||||
package org.elasticsearch.repositories.gcs;
|
package org.elasticsearch.repositories.gcs;
|
||||||
|
|
||||||
|
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||||
|
import com.google.api.client.http.GenericUrl;
|
||||||
|
import com.google.api.client.http.HttpIOExceptionHandler;
|
||||||
|
import com.google.api.client.http.HttpRequest;
|
||||||
|
import com.google.api.client.http.HttpRequestFactory;
|
||||||
|
import com.google.api.client.http.HttpRequestInitializer;
|
||||||
|
import com.google.api.client.http.HttpResponse;
|
||||||
|
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
|
||||||
|
import com.google.api.client.testing.http.MockHttpTransport;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.env.TestEnvironment;
|
||||||
|
import org.elasticsearch.repositories.gcs.GoogleCloudStorageService.InternalGoogleCloudStorageService;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
import static java.util.Collections.emptyMap;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import static java.util.Collections.singletonMap;
|
||||||
import org.elasticsearch.env.Environment;
|
import static org.mockito.Matchers.any;
|
||||||
import org.elasticsearch.env.TestEnvironment;
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
import org.elasticsearch.repositories.gcs.GoogleCloudStorageService.InternalGoogleCloudStorageService;
|
import static org.mockito.Mockito.mock;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class GoogleCloudStorageServiceTests extends ESTestCase {
|
public class GoogleCloudStorageServiceTests extends ESTestCase {
|
||||||
|
|
||||||
|
@ -47,13 +65,56 @@ public class GoogleCloudStorageServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assertSame(cred, service.getCredential("default"));
|
assertSame(cred, service.getCredential("default"));
|
||||||
|
|
||||||
|
service.new DefaultHttpRequestInitializer(cred, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testClientCredential() throws Exception {
|
public void testClientCredential() throws Exception {
|
||||||
GoogleCredential cred = GoogleCredential.fromStream(getDummyCredentialStream());
|
GoogleCredential cred = GoogleCredential.fromStream(getDummyCredentialStream());
|
||||||
Map<String, GoogleCredential> credentials = Collections.singletonMap("clientname", cred);
|
Map<String, GoogleCredential> credentials = singletonMap("clientname", cred);
|
||||||
Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
|
Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
|
||||||
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, credentials);
|
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, credentials);
|
||||||
assertSame(cred, service.getCredential("clientname"));
|
assertSame(cred, service.getCredential("clientname"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the {@link InternalGoogleCloudStorageService.DefaultHttpRequestInitializer} attaches new instances
|
||||||
|
* of {@link HttpIOExceptionHandler} and {@link HttpUnsuccessfulResponseHandler} for every HTTP requests.
|
||||||
|
*/
|
||||||
|
public void testDefaultHttpRequestInitializer() throws IOException {
|
||||||
|
final Environment environment = mock(Environment.class);
|
||||||
|
when(environment.settings()).thenReturn(Settings.EMPTY);
|
||||||
|
|
||||||
|
final GoogleCredential credential = mock(GoogleCredential.class);
|
||||||
|
when(credential.handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean())).thenReturn(false);
|
||||||
|
|
||||||
|
final TimeValue readTimeout = TimeValue.timeValueSeconds(randomIntBetween(1, 120));
|
||||||
|
final TimeValue connectTimeout = TimeValue.timeValueSeconds(randomIntBetween(1, 120));
|
||||||
|
|
||||||
|
final InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(environment, emptyMap());
|
||||||
|
final HttpRequestInitializer initializer = service.new DefaultHttpRequestInitializer(credential, connectTimeout, readTimeout);
|
||||||
|
final HttpRequestFactory requestFactory = new MockHttpTransport().createRequestFactory(initializer);
|
||||||
|
|
||||||
|
final HttpRequest request1 = requestFactory.buildGetRequest(new GenericUrl());
|
||||||
|
assertEquals((int) connectTimeout.millis(), request1.getConnectTimeout());
|
||||||
|
assertEquals((int) readTimeout.millis(), request1.getReadTimeout());
|
||||||
|
assertSame(credential, request1.getInterceptor());
|
||||||
|
assertNotNull(request1.getIOExceptionHandler());
|
||||||
|
assertNotNull(request1.getUnsuccessfulResponseHandler());
|
||||||
|
|
||||||
|
final HttpRequest request2 = requestFactory.buildGetRequest(new GenericUrl());
|
||||||
|
assertEquals((int) connectTimeout.millis(), request2.getConnectTimeout());
|
||||||
|
assertEquals((int) readTimeout.millis(), request2.getReadTimeout());
|
||||||
|
assertSame(request1.getInterceptor(), request2.getInterceptor());
|
||||||
|
assertNotNull(request2.getIOExceptionHandler());
|
||||||
|
assertNotSame(request1.getIOExceptionHandler(), request2.getIOExceptionHandler());
|
||||||
|
assertNotNull(request2.getUnsuccessfulResponseHandler());
|
||||||
|
assertNotSame(request1.getUnsuccessfulResponseHandler(), request2.getUnsuccessfulResponseHandler());
|
||||||
|
|
||||||
|
request1.getUnsuccessfulResponseHandler().handleResponse(null, null, false);
|
||||||
|
verify(credential, times(1)).handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean());
|
||||||
|
|
||||||
|
request2.getUnsuccessfulResponseHandler().handleResponse(null, null, false);
|
||||||
|
verify(credential, times(2)).handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue