Better handling of exceptions and retrying behavior in case of read timeout. (Default connection timeout is 10s and read timeout now is 60s)
This commit is contained in:
parent
d761dac8ac
commit
7790eb127c
|
@ -15,7 +15,6 @@
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="module" value="true"/>
|
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
@ -32,5 +31,11 @@
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
<classpathentry kind="output" path="target/classes"/>
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<faceted-project>
|
<faceted-project>
|
||||||
<runtime name="Liferay v6.2 (Tomcat 7)"/>
|
|
||||||
<installed facet="jst.utility" version="1.0"/>
|
<installed facet="jst.utility" version="1.0"/>
|
||||||
<installed facet="java" version="1.8"/>
|
<installed facet="java" version="11"/>
|
||||||
</faceted-project>
|
</faceted-project>
|
||||||
|
|
|
@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||||
- Restored correct behavior for event publishing with workflow id only sent back
|
- Restored correct behavior for event publishing with workflow id only sent back
|
||||||
- Extracted `AbstractHTTPWithJWTTokenAuthEventSender` class for easy subclassing
|
- Extracted `AbstractHTTPWithJWTTokenAuthEventSender` class for easy subclassing
|
||||||
- Added new outcome check methods to inspect last send and last check actions results and some other facilities
|
- Added new outcome check methods to inspect last send and last check actions results and some other facilities
|
||||||
|
- Better handling of exceptions and retrying behavior in case of read timeout. (Default connection timeout is 10s and read timeout now is 60s)
|
||||||
|
|
||||||
## [v1.1.0]
|
## [v1.1.0]
|
||||||
- Added `BufferedEventProcessor` to manual send bunch of events and controlling their output status (#23628)
|
- Added `BufferedEventProcessor` to manual send bunch of events and controlling their output status (#23628)
|
||||||
|
|
7
pom.xml
7
pom.xml
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>maven-parent</artifactId>
|
<artifactId>maven-parent</artifactId>
|
||||||
<groupId>org.gcube.tools</groupId>
|
<groupId>org.gcube.tools</groupId>
|
||||||
<version>1.2.1-SNAPSHOT</version>
|
<version>1.2.0</version>
|
||||||
<relativePath />
|
<relativePath />
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -33,6 +33,11 @@
|
||||||
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
|
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
|
||||||
<url>https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
|
<url>https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
|
||||||
</scm>
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
|
@ -44,7 +44,7 @@ public abstract class AbstractEventPublisher implements EventPublisher {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLastPublishEventHTTPResponseCode() {
|
public int getLastPublishEventHTTPResponseCode() {
|
||||||
return eventSender.getLastSendHTTPResponseCode();
|
return getEventSender().getLastSendHTTPResponseCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,7 +88,7 @@ public abstract class AbstractEventPublisher implements EventPublisher {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLastCheckHTTPResponseCode() {
|
public int getLastCheckHTTPResponseCode() {
|
||||||
return eventSender.getLastRetrieveHTTPResponseCode();
|
return getEventSender().getLastRetrieveHTTPResponseCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract EventSender createEventSender();
|
protected abstract EventSender createEventSender();
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@ -32,21 +33,20 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
public AbstractHTTPWithJWTTokenAuthEventSender(URL baseEndpointURL, String clientId, String clientSecret,
|
public AbstractHTTPWithJWTTokenAuthEventSender(URL baseEndpointURL, String clientId, String clientSecret,
|
||||||
URL tokenURL) {
|
URL tokenURL) {
|
||||||
|
|
||||||
|
this(baseEndpointURL, clientId, clientSecret, tokenURL, HTTPVerb.DEFAULT_CONNECTION_TIMEOUT,
|
||||||
|
HTTPVerb.DEFAULT_READ_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractHTTPWithJWTTokenAuthEventSender(URL baseEndpointURL, String clientId, String clientSecret,
|
||||||
|
URL tokenURL, int connectionTimeout, int readTimeout) {
|
||||||
|
|
||||||
super();
|
super();
|
||||||
this.baseEndpointURL = baseEndpointURL;
|
this.baseEndpointURL = baseEndpointURL;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.clientSecret = clientSecret;
|
this.clientSecret = clientSecret;
|
||||||
this.tokenURL = tokenURL;
|
this.tokenURL = tokenURL;
|
||||||
this.connectionTimeout = getDefaultConnectionTimeout();
|
this.connectionTimeout = connectionTimeout;
|
||||||
this.readTimeout = getDefaultReadTimeout();
|
this.readTimeout = readTimeout;
|
||||||
}
|
|
||||||
|
|
||||||
protected int getDefaultReadTimeout() {
|
|
||||||
return HTTPVerb.DEFAULT_READ_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getDefaultConnectionTimeout() {
|
|
||||||
return HTTPVerb.DEFAULT_CONNECTION_TIMEOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getReadTimeout() {
|
public int getReadTimeout() {
|
||||||
|
@ -112,7 +112,7 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
public abstract class HTTPVerb {
|
public abstract class HTTPVerb {
|
||||||
|
|
||||||
protected static final int DEFAULT_CONNECTION_TIMEOUT = 10000;
|
protected static final int DEFAULT_CONNECTION_TIMEOUT = 10000;
|
||||||
protected static final int DEFAULT_READ_TIMEOUT = 5000;
|
protected static final int DEFAULT_READ_TIMEOUT = 60000;
|
||||||
|
|
||||||
protected URL baseEndpoint;
|
protected URL baseEndpoint;
|
||||||
protected int httpResponseCode = -1;
|
protected int httpResponseCode = -1;
|
||||||
|
@ -130,8 +130,10 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
|
|
||||||
public class HTTPPost extends HTTPVerb implements Runnable {
|
public class HTTPPost extends HTTPVerb implements Runnable {
|
||||||
|
|
||||||
private static final int PAUSE_INCREMENT_FACTOR = 2;
|
private static final int FIRST_PAUSE = 7500; // ms
|
||||||
private static final long MAX_RETRYINGS = 2;
|
private static final int PAUSE_INCREMENT_FACTOR = 4;
|
||||||
|
private static final long MAX_RETRYINGS = 5;
|
||||||
|
private static final boolean RETRY_ON_READ_TIMEOUT = false;
|
||||||
|
|
||||||
private final int[] RETRY_CODES = { HttpURLConnection.HTTP_BAD_GATEWAY,
|
private final int[] RETRY_CODES = { HttpURLConnection.HTTP_BAD_GATEWAY,
|
||||||
HttpURLConnection.HTTP_CLIENT_TIMEOUT, HttpURLConnection.HTTP_GATEWAY_TIMEOUT,
|
HttpURLConnection.HTTP_CLIENT_TIMEOUT, HttpURLConnection.HTTP_GATEWAY_TIMEOUT,
|
||||||
|
@ -139,7 +141,7 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
|
|
||||||
private Event event;
|
private Event event;
|
||||||
private String result;
|
private String result;
|
||||||
private long actualPause = 1;
|
private long actualPause = FIRST_PAUSE;
|
||||||
private long retryings = 0;
|
private long retryings = 0;
|
||||||
|
|
||||||
public HTTPPost(URL baseEndpoint, Event event) {
|
public HTTPPost(URL baseEndpoint, Event event) {
|
||||||
|
@ -154,7 +156,8 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
if (baseEndpoint.toString().endsWith("/")) {
|
if (baseEndpoint.toString().endsWith("/")) {
|
||||||
try {
|
try {
|
||||||
log.debug("Removing trailing slash from base URL since the endpoint computation API changed");
|
log.debug("Removing trailing slash from base URL since the endpoint computation API changed");
|
||||||
eventEndpoint = new URL(baseEndpoint.toString().substring(0, baseEndpoint.toString().length() - 1));
|
eventEndpoint = new URL(
|
||||||
|
baseEndpoint.toString().substring(0, baseEndpoint.toString().length() - 1));
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
log.error("Cannot remove trailing slash from base endpoint URL", e);
|
log.error("Cannot remove trailing slash from base endpoint URL", e);
|
||||||
return;
|
return;
|
||||||
|
@ -206,45 +209,60 @@ public abstract class AbstractHTTPWithJWTTokenAuthEventSender implements EventSe
|
||||||
} else {
|
} else {
|
||||||
isr = new InputStreamReader(connection.getErrorStream(), "UTF-8");
|
isr = new InputStreamReader(connection.getErrorStream(), "UTF-8");
|
||||||
}
|
}
|
||||||
BufferedReader br = new BufferedReader(isr);
|
try {
|
||||||
String line = null;
|
BufferedReader br = new BufferedReader(isr);
|
||||||
while ((line = br.readLine()) != null) {
|
String line = null;
|
||||||
sb.append("\n" + line);
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append("\n" + line);
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
isr.close();
|
||||||
|
sb.deleteCharAt(0);
|
||||||
|
result = sb.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error reading response", e);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
br.close();
|
|
||||||
isr.close();
|
|
||||||
sb.deleteCharAt(0);
|
|
||||||
result = sb.toString();
|
|
||||||
if (OK) {
|
if (OK) {
|
||||||
log.debug("[{}] Event publish for {} is OK", httpResponseCode, event.getName());
|
log.debug("[{}] Event publish for {} is OK", httpResponseCode, event.getName());
|
||||||
} else {
|
} else {
|
||||||
log.trace("Response message from server:\n{}", result);
|
log.trace("Response message from server:\n{}", result);
|
||||||
if (shouldRetryWithCode(httpResponseCode)) {
|
if (shouldRetryWithCode(httpResponseCode)) {
|
||||||
if (retryings <= MAX_RETRYINGS) {
|
log.warn("[{}] Event publish ERROR", httpResponseCode);
|
||||||
log.warn("[{}] Event publish ERROR, retrying in {} seconds", httpResponseCode,
|
|
||||||
actualPause);
|
|
||||||
|
|
||||||
Thread.sleep(actualPause * 1000);
|
|
||||||
log.debug("Start retrying event publish: {}", event.getName());
|
|
||||||
actualPause *= PAUSE_INCREMENT_FACTOR;
|
|
||||||
retryings += 1;
|
|
||||||
} else {
|
|
||||||
log.error("[{}] Event publish ERROR, exhausted tries after {} retryings",
|
|
||||||
httpResponseCode,
|
|
||||||
retryings);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.info("[{}] Event publish ERROR but should not retry with this HTTP code",
|
log.info("[{}] Event publish ERROR but not retrying to send it with this HTTP code",
|
||||||
httpResponseCode);
|
httpResponseCode);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (SocketTimeoutException e) {
|
||||||
|
log.error("Read timeout POSTing JSON to: " + eventEndpoint, e);
|
||||||
|
if (RETRY_ON_READ_TIMEOUT) {
|
||||||
|
log.trace("Event will be re-sent accodingly to retryes");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.trace("Event will be not re-sent");
|
||||||
|
break;
|
||||||
|
}
|
||||||
} catch (IOException | OpenIdConnectRESTHelperException e) {
|
} catch (IOException | OpenIdConnectRESTHelperException e) {
|
||||||
log.error("POSTing JSON to: " + eventEndpoint, e);
|
log.error("I/O Error POSTing JSON to: " + eventEndpoint, e);
|
||||||
break;
|
}
|
||||||
|
if (!OK) {
|
||||||
|
if (retryings <= MAX_RETRYINGS) {
|
||||||
|
log.info("Retrying to send event in {} ms", actualPause);
|
||||||
|
|
||||||
|
Thread.sleep(actualPause);
|
||||||
|
log.debug("Start retrying event publish: {}", event.getName());
|
||||||
|
actualPause *= PAUSE_INCREMENT_FACTOR;
|
||||||
|
retryings += 1;
|
||||||
|
} else {
|
||||||
|
log.error("[{}] Event publish ERROR, exhausted tries after {} retryings",
|
||||||
|
httpResponseCode,
|
||||||
|
retryings);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (!OK);
|
} while (!OK);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
Loading…
Reference in New Issue