feat: 🎸 Configurable timeouts in RPC connector

use properties:
* perun.rpc.connectionRequestTimeout (def: 30 000ms) - how long we can
  wait until we get connection from pool
* perun.rpc.connectionTimeout (def: 30 000ms) - how long we can wait
  until connection is established
* perun.rpc.responseTimeout (def: 60 000ms) - how long we can wait for
  response
pull/1580/head
Dominik František Bučík 2022-07-28 11:13:10 +02:00
parent 74545d7ca2
commit a929858026
No known key found for this signature in database
GPG Key ID: 73F752BEC0709845
2 changed files with 59 additions and 16 deletions

View File

@ -46,6 +46,9 @@
<prop key="perun.rpc.user">xxxxx</prop> <prop key="perun.rpc.user">xxxxx</prop>
<prop key="perun.rpc.password">yyyyy</prop> <prop key="perun.rpc.password">yyyyy</prop>
<prop key="perun.rpc.serializer">json</prop> <prop key="perun.rpc.serializer">json</prop>
<prop key="perun.rpc.connectionRequestTimeout">30000</prop>
<prop key="perun.rpc.connectionTimeout">30000</prop>
<prop key="perun.rpc.responseTimeout">60000</prop>
<!-- LDAP --> <!-- LDAP -->
<prop key="ldap.host">perun.cesnet.cz</prop> <prop key="ldap.host">perun.cesnet.cz</prop>
<prop key="ldap.user">xxxxx</prop> <prop key="ldap.user">xxxxx</prop>
@ -500,11 +503,14 @@
<!-- communicates with Perun --> <!-- communicates with Perun -->
<bean id="perunConnectorRpc" class="cz.muni.ics.oidc.server.connectors.PerunConnectorRpc"> <bean id="perunConnectorRpc" class="cz.muni.ics.oidc.server.connectors.PerunConnectorRpc">
<constructor-arg name="perunUrl" value="${perun.rpc.url}"/> <constructor-arg name="url" value="${perun.rpc.url}"/>
<constructor-arg name="perunUser" value="${perun.rpc.user}"/> <constructor-arg name="username" value="${perun.rpc.user}"/>
<constructor-arg name="perunPassword" value="${perun.rpc.password}"/> <constructor-arg name="password" value="${perun.rpc.password}"/>
<constructor-arg name="enabled" value="${perun.rpc.enabled}"/> <constructor-arg name="enabled" value="${perun.rpc.enabled}"/>
<constructor-arg name="serializer" value="${perun.rpc.serializer}"/> <constructor-arg name="serializer" value="${perun.rpc.serializer}"/>
<constructor-arg name="connectionRequestTimeout" value="${perun.rpc.connectionRequestTimeout}"/>
<constructor-arg name="connectionTimeout" value="${perun.rpc.connectionTimeout}"/>
<constructor-arg name="responseTimeout" value="${perun.rpc.responseTimeout}"/>
</bean> </bean>
<bean id="perunAdapterMethodsRpc" class="cz.muni.ics.oidc.server.adapters.impl.PerunAdapterRpc"> <bean id="perunAdapterMethodsRpc" class="cz.muni.ics.oidc.server.adapters.impl.PerunAdapterRpc">

View File

@ -12,6 +12,7 @@ import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.http.HeaderElement; import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator; import org.apache.http.HeaderElementIterator;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -51,17 +52,32 @@ public class PerunConnectorRpc {
private String perunPassword; private String perunPassword;
private boolean isEnabled; private boolean isEnabled;
private String serializer; private String serializer;
private int connectionRequestTimeout = 30000;
private int connectionTimeout = 30000;
private int responseTimeout = 60000;
private RestTemplate restTemplate; private RestTemplate restTemplate;
public PerunConnectorRpc(String perunUrl, String perunUser, String perunPassword, String enabled, String serializer) { public PerunConnectorRpc(String url,
String username,
String password,
String enabled,
String serializer,
int connectionRequestTimeout,
int connectionTimeout,
int responseTimeout)
{
this.isEnabled = Boolean.parseBoolean(enabled); this.isEnabled = Boolean.parseBoolean(enabled);
this.setPerunUrl(perunUrl); this.setPerunUrl(url);
this.setPerunUser(perunUser); this.setPerunUser(username);
this.setPerunPassword(perunPassword); this.setPerunPassword(password);
this.setSerializer(serializer); this.setSerializer(serializer);
this.setConnectionRequestTimeout(connectionRequestTimeout);
this.setConnectionTimeout(connectionTimeout);
this.setResponseTimeout(responseTimeout);
} }
public void setEnabled(String enabled) { private void setEnabled(String enabled) {
this.isEnabled = Boolean.parseBoolean(enabled); this.isEnabled = Boolean.parseBoolean(enabled);
} }
@ -69,7 +85,7 @@ public class PerunConnectorRpc {
return isEnabled; return isEnabled;
} }
public void setPerunUrl(String perunUrl) { private void setPerunUrl(String perunUrl) {
if (!StringUtils.hasText(perunUrl)) { if (!StringUtils.hasText(perunUrl)) {
throw new IllegalArgumentException("Perun URL cannot be null or empty"); throw new IllegalArgumentException("Perun URL cannot be null or empty");
} else if (perunUrl.endsWith("/")) { } else if (perunUrl.endsWith("/")) {
@ -79,7 +95,7 @@ public class PerunConnectorRpc {
this.perunUrl = perunUrl; this.perunUrl = perunUrl;
} }
public void setPerunUser(String perunUser) { private void setPerunUser(String perunUser) {
if (!StringUtils.hasText(perunUser)) { if (!StringUtils.hasText(perunUser)) {
throw new IllegalArgumentException("Perun USER cannot be null or empty"); throw new IllegalArgumentException("Perun USER cannot be null or empty");
} }
@ -87,7 +103,7 @@ public class PerunConnectorRpc {
this.perunUser = perunUser; this.perunUser = perunUser;
} }
public void setPerunPassword(String perunPassword) { private void setPerunPassword(String perunPassword) {
if (!StringUtils.hasText(perunPassword)) { if (!StringUtils.hasText(perunPassword)) {
throw new IllegalArgumentException("Perun PASSWORD cannot be null or empty"); throw new IllegalArgumentException("Perun PASSWORD cannot be null or empty");
} }
@ -95,22 +111,43 @@ public class PerunConnectorRpc {
this.perunPassword = perunPassword; this.perunPassword = perunPassword;
} }
public void setSerializer(String serializer) { private void setSerializer(String serializer) {
if (!StringUtils.hasText(serializer)) { if (!StringUtils.hasText(serializer)) {
this.serializer = "json"; serializer = "json";
} }
this.serializer = serializer; this.serializer = serializer;
} }
private void setConnectionRequestTimeout(int connectionRequestTimeout) {
if (0 >= connectionRequestTimeout) {
throw new IllegalArgumentException("Connection request timeout must be greater than 0ms");
}
this.connectionRequestTimeout = connectionRequestTimeout;
}
private void setConnectionTimeout(int connectionTimeout) {
if (0 >= connectionTimeout) {
throw new IllegalArgumentException("Connection timeout must be greater than 0ms");
}
this.connectionTimeout = connectionTimeout;
}
private void setResponseTimeout(int responseTimeout) {
if (0 >= responseTimeout) {
throw new IllegalArgumentException("Response timeout must be greater than 0ms");
}
this.responseTimeout = responseTimeout;
}
@PostConstruct @PostConstruct
public void postInit() { public void postInit() {
restTemplate = new RestTemplate(); restTemplate = new RestTemplate();
//HTTP connection pooling, see https://howtodoinjava.com/spring-restful/resttemplate-httpclient-java-config/ //HTTP connection pooling, see https://howtodoinjava.com/spring-restful/resttemplate-httpclient-java-config/
RequestConfig requestConfig = RequestConfig.custom() RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(30000) // The timeout when requesting a connection from the connection manager .setConnectionRequestTimeout(this.connectionRequestTimeout) // The timeout when requesting a connection from the connection manager
.setConnectTimeout(30000) // Determines the timeout in milliseconds until a connection is established .setConnectTimeout(this.connectionTimeout) // Determines the timeout in milliseconds until a connection is established
.setSocketTimeout(60000) // The timeout for waiting for data .setSocketTimeout(this.responseTimeout) // The timeout for waiting for data
.build(); .build();
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(); PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
poolingConnectionManager.setMaxTotal(20); // maximum connections total poolingConnectionManager.setMaxTotal(20); // maximum connections total