better GOAWAY handling
This commit is contained in:
parent
ab20035583
commit
3d5e2bc26a
5 changed files with 55 additions and 29 deletions
|
@ -1,3 +1,3 @@
|
||||||
group = org.xbib
|
group = org.xbib
|
||||||
name = oai
|
name = oai
|
||||||
version = 4.0.0
|
version = 4.0.1
|
||||||
|
|
|
@ -26,6 +26,7 @@ test {
|
||||||
systemProperty 'io.netty.recycler.maxCapacityPerThread', '0'
|
systemProperty 'io.netty.recycler.maxCapacityPerThread', '0'
|
||||||
systemProperty 'io.netty.transport.noNative', 'true'
|
systemProperty 'io.netty.transport.noNative', 'true'
|
||||||
testLogging {
|
testLogging {
|
||||||
|
showStandardStreams = true
|
||||||
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
||||||
}
|
}
|
||||||
afterSuite { desc, result ->
|
afterSuite { desc, result ->
|
||||||
|
|
|
@ -198,17 +198,31 @@ public class OAIClient {
|
||||||
.build();
|
.build();
|
||||||
logger.log(Level.INFO, "sending " + httpRequest);
|
logger.log(Level.INFO, "sending " + httpRequest);
|
||||||
if (consumer != null) {
|
if (consumer != null) {
|
||||||
HttpResponse<byte[]> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
|
int retrycount = 3;
|
||||||
int status = httpResponse.statusCode();
|
HttpResponse<byte[]> httpResponse = null;
|
||||||
String contentType = httpResponse.headers().firstValue("content-type").orElse(null);
|
while (httpResponse == null && retrycount > 0) {
|
||||||
String retryAfter = httpResponse.headers().firstValue("retry-after").orElse(null);
|
try {
|
||||||
String body = new String(httpResponse.body(), StandardCharsets.UTF_8);
|
httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
|
||||||
listRecordsResponse.receivedResponse(body, status, contentType, retryAfter, splitWriter);
|
} catch (IOException e) {
|
||||||
logger.log(Level.FINE, "response headers = " + httpResponse.headers() +
|
// e.g. java.io.IOException: GOAWAY received
|
||||||
" resumption-token = " + listRecordsResponse.getResumptionToken());
|
// at java.net.http/jdk.internal.net.http.HttpClientImpl.send(Unknown Source)
|
||||||
byte[] b = httpResponse.body();
|
logger.log(Level.WARNING, e.getMessage(), e);
|
||||||
if (b.length > 0) {
|
retrycount--;
|
||||||
consumer.accept(new ByteArrayInputStream(b));
|
Thread.sleep(5000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (httpResponse != null) {
|
||||||
|
int status = httpResponse.statusCode();
|
||||||
|
String contentType = httpResponse.headers().firstValue("content-type").orElse(null);
|
||||||
|
String retryAfter = httpResponse.headers().firstValue("retry-after").orElse(null);
|
||||||
|
String body = new String(httpResponse.body(), StandardCharsets.UTF_8);
|
||||||
|
listRecordsResponse.receivedResponse(body, status, contentType, retryAfter, splitWriter);
|
||||||
|
logger.log(Level.FINE, "response headers = " + httpResponse.headers() +
|
||||||
|
" resumption-token = " + listRecordsResponse.getResumptionToken());
|
||||||
|
byte[] b = httpResponse.body();
|
||||||
|
if (b.length > 0) {
|
||||||
|
consumer.accept(new ByteArrayInputStream(b));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
|
@ -18,6 +18,8 @@ import java.io.StringWriter;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
|
@ -28,6 +30,8 @@ import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
public class ListRecordsResponse implements OAIResponse {
|
public class ListRecordsResponse implements OAIResponse {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ListRecordsResponse.class.getName());
|
||||||
|
|
||||||
private final ListRecordsRequest request;
|
private final ListRecordsRequest request;
|
||||||
|
|
||||||
private ListRecordsFilterReader filterreader;
|
private ListRecordsFilterReader filterreader;
|
||||||
|
@ -54,35 +58,44 @@ public class ListRecordsResponse implements OAIResponse {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receivedResponse(String message, int status, String contentType, String retryAfter, SplitWriter splitWriter) throws OAIException {
|
public void receivedResponse(String message,
|
||||||
if (status == 503) {
|
int status,
|
||||||
long secs = retryAfterMillis / 1000;
|
String contentType,
|
||||||
if (retryAfter != null) {
|
String retryAfter,
|
||||||
|
SplitWriter splitWriter) throws OAIException {
|
||||||
|
long secs = retryAfterMillis / 1000;
|
||||||
|
if (retryAfter != null) {
|
||||||
|
if (!isDigits(retryAfter)) {
|
||||||
|
// parse RFC date, e.g. Fri, 31 Dec 1999 23:59:59 GMT
|
||||||
|
Instant instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(retryAfter));
|
||||||
|
secs = ChronoUnit.SECONDS.between(instant, Instant.now());
|
||||||
|
} else {
|
||||||
secs = Long.parseLong(retryAfter);
|
secs = Long.parseLong(retryAfter);
|
||||||
if (!isDigits(retryAfter)) {
|
|
||||||
// parse RFC date, e.g. Fri, 31 Dec 1999 23:59:59 GMT
|
|
||||||
Instant instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(retryAfter));
|
|
||||||
secs = ChronoUnit.SECONDS.between(instant, Instant.now());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
request.setRetry(true);
|
request.setRetry(true);
|
||||||
|
}
|
||||||
|
if (status == 503) {
|
||||||
try {
|
try {
|
||||||
if (secs > 0L) {
|
if (secs > 0L) {
|
||||||
|
logger.log(Level.INFO, "waiting " + secs + " seconds");
|
||||||
Thread.sleep(1000 * secs);
|
Thread.sleep(1000 * secs);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
// early return
|
||||||
return;
|
return;
|
||||||
}
|
} else if (status == 429) {
|
||||||
if (status == 429) {
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(10000L);
|
if (secs > 0L) {
|
||||||
|
logger.log(Level.INFO, "waiting " + secs + " seconds");
|
||||||
|
Thread.sleep(1000 * secs);
|
||||||
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// ignore
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
// do not return, try to evaluate returned message if present
|
||||||
if (status != 200) {
|
} else if (status != 200) {
|
||||||
throw new OAIException("status = " + status + " response = " + message);
|
throw new OAIException("status = " + status + " response = " + message);
|
||||||
}
|
}
|
||||||
// activate XSLT only if OAI XML content type is returned
|
// activate XSLT only if OAI XML content type is returned
|
||||||
|
@ -138,5 +151,4 @@ public class ListRecordsResponse implements OAIResponse {
|
||||||
public ResumptionToken<?> getResumptionToken() {
|
public ResumptionToken<?> getResumptionToken() {
|
||||||
return filterreader != null ? filterreader.getResumptionToken() : null;
|
return filterreader != null ? filterreader.getResumptionToken() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import org.xbib.oai.client.SplitWriter;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@Disabled("port is locked")
|
|
||||||
class DNBClientTest {
|
class DNBClientTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in a new issue