When implementing retries for Compute client one needs to read and parse HttpResponse as JSON in order to find rateLimitExceeded error in details (we could rely on the status code but unfortunately it's a generic 403 Forbidden in this case). Later when the library attempts to read the response again to throw GoogleJsonResponseException it won't be able to fill details field because the HTTP content has been already read (it also printStackTraces an IOException) .
private HttpBackOffUnsuccessfulResponseHandler createRetryHandler() {
BackOff backOff = new ExponentialBackOff.Builder()
.setInitialIntervalMillis(1000)
.setMaxIntervalMillis(5000)
.setMaxElapsedTimeMillis(60_000)
.build();
HttpBackOffUnsuccessfulResponseHandler retryHandler = new HttpBackOffUnsuccessfulResponseHandler(backOff) {
@Override
public boolean handleResponse(HttpRequest request, HttpResponse response, boolean supportsRetry)
throws IOException {
return httpCredentialsAdapter.handleResponse(request, response, supportsRetry) ||
super.handleResponse(request, response, supportsRetry);
}
};
retryHandler.setBackOffRequired(resp -> {
GoogleJsonResponseException exc = GoogleJsonResponseException.from(JacksonFactory.getDefaultInstance(),
resp);
return
exc.getDetails().getErrors().stream().anyMatch(err -> "rateLimitExceeded".equals(err.getReason()));
});
return retryHandler;
}
java.io.IOException: Stream closed
at java.base/java.util.zip.GZIPInputStream.ensureOpen(GZIPInputStream.java:63)
at java.base/java.util.zip.GZIPInputStream.read(GZIPInputStream.java:114)
at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:70)
at com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.ensureLoaded(ByteSourceJsonBootstrapper.java:539)
at com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.detectEncoding(ByteSourceJsonBootstrapper.java:133)
at com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.constructParser(ByteSourceJsonBootstrapper.java:256)
at com.fasterxml.jackson.core.JsonFactory._createParser(JsonFactory.java:1656)
at com.fasterxml.jackson.core.JsonFactory.createParser(JsonFactory.java:1085)
at com.fasterxml.jackson.core.JsonFactory.createJsonParser(JsonFactory.java:1466)
at com.google.api.client.json.jackson2.JacksonFactory.createJsonParser(JacksonFactory.java:85)
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:102)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:118)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:37)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:428)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1108)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:514)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:455)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:565)
When implementing retries for Compute client one needs to read and parse
HttpResponseas JSON in order to findrateLimitExceedederror in details (we could rely on the status code but unfortunately it's a generic403 Forbiddenin this case). Later when the library attempts to read the response again to throwGoogleJsonResponseExceptionit won't be able to filldetailsfield because the HTTP content has been already read (it alsoprintStackTraces anIOException) .