Skip to content

Commit

Permalink
IdleConnectionsEndpoint now accepts a single Duration argument, and d…
Browse files Browse the repository at this point in the history
…efaults to the value of the connect.api.close-idle-connections.idle-time property
  • Loading branch information
robtimus committed Aug 6, 2023
1 parent 9aba9b4 commit 3a3c847
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public class ConnectionsEndpoint {
public ConnectionsEndpoint(ApplicationContext context) {
this.context = context;

idleConnectionsEndpoint = new IdleConnectionsEndpoint(context);
// The default idle time is not used here, as an explicit idle time is required in this endpoint
idleConnectionsEndpoint = new IdleConnectionsEndpoint(context, 0);
expiredConnectionsEndpoint = new ExpiredConnectionsEndpoint(context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

package com.github.robtimus.connect.sdk.java.springboot.actuator;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.Nullable;
import com.ingenico.connect.gateway.sdk.java.Client;
import com.ingenico.connect.gateway.sdk.java.Communicator;
import com.ingenico.connect.gateway.sdk.java.PooledConnection;
Expand All @@ -36,18 +38,24 @@
@SuppressWarnings("javadoc")
public class IdleConnectionsEndpoint extends CloseConnectionsEndpoint {

public IdleConnectionsEndpoint(ApplicationContext context) {
private final long defaultIdleTimeInMillis;

public IdleConnectionsEndpoint(ApplicationContext context, long defaultIdleTimeInMillis) {
super(context);
this.defaultIdleTimeInMillis = defaultIdleTimeInMillis;
}

/**
* Closes all idle connections for all {@link PooledConnection}, {@link Communicator} and {@link Client} beans.
*
* @param idleTime The idle time.
* @param timeUnit The time unit.
*/
@DeleteOperation
public void closeIdleConnections(Long idleTime, TimeUnit timeUnit) {
public void closeIdleConnections(@Nullable Duration idleTime) {
closeIdleConnections(toMillis(idleTime), TimeUnit.MILLISECONDS);
}

void closeIdleConnections(long idleTime, TimeUnit timeUnit) {
closeConnections(
connection -> connection.closeIdleConnections(idleTime, timeUnit),
communicator -> communicator.closeIdleConnections(idleTime, timeUnit),
Expand All @@ -59,13 +67,22 @@ public void closeIdleConnections(Long idleTime, TimeUnit timeUnit) {
*
* @param beanName The name of the {@link PooledConnection}, {@link Communicator} or {@link Client} bean.
* @param idleTime The idle time.
* @param timeUnit The time unit.
*/
@DeleteOperation
public void closeIdleConnectionsForBean(@Selector String beanName, Long idleTime, TimeUnit timeUnit) {
public void closeIdleConnectionsForBean(@Selector String beanName, @Nullable Duration idleTime) {
closeIdleConnectionsForBean(beanName, toMillis(idleTime), TimeUnit.MILLISECONDS);
}

void closeIdleConnectionsForBean(String beanName, long idleTime, TimeUnit timeUnit) {
closeConnectionsForBean(beanName,
connection -> connection.closeIdleConnections(idleTime, timeUnit),
communicator -> communicator.closeIdleConnections(idleTime, timeUnit),
client -> client.closeIdleConnections(idleTime, timeUnit));
}

private long toMillis(Duration idleTime) {
return idleTime != null
? idleTime.toMillis()
: defaultIdleTimeInMillis;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,13 @@ private Set<String> getHttpsProtocols() {
@EnableScheduling
static class ConnectionManager {

static final String IDLE_TIME = "${connect.api.close-idle-connections.idle-time:20000}";
private static final String INTERVAL = "${connect.api.close-idle-connections.interval:10000}";

private final PooledConnection connection;
private final long idleTime;

ConnectionManager(PooledConnection connection, @Value("${connect.api.close-idle-connections.idle-time:20000}") long idleTime) {
ConnectionManager(PooledConnection connection, @Value(IDLE_TIME) long idleTime) {
this.connection = Objects.requireNonNull(connection);
this.idleTime = idleTime;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package com.github.robtimus.connect.sdk.java.springboot.autoconfigure;

import static com.github.robtimus.connect.sdk.java.springboot.autoconfigure.ConnectSdkConnectionAutoConfiguration.ConnectionManager.IDLE_TIME;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
Expand Down Expand Up @@ -54,8 +56,8 @@ public ConnectionsEndpoint connectSdkConnectionsEndpoint(ApplicationContext cont
@Bean
@ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint(endpoint = IdleConnectionsEndpoint.class)
public IdleConnectionsEndpoint idleConnectSdkConnectionsEndpoint(ApplicationContext context) {
return new IdleConnectionsEndpoint(context);
public IdleConnectionsEndpoint idleConnectSdkConnectionsEndpoint(ApplicationContext context, @Value(IDLE_TIME) long defaultIdleTimeInMillis) {
return new IdleConnectionsEndpoint(context, defaultIdleTimeInMillis);
}

@Bean
Expand Down
21 changes: 13 additions & 8 deletions src/site/xhtml/actuator-endpoints.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,24 @@ curl -X POST http://&lt;host&gt;/actuator/connectSdkLogging/myBean -H Content-Ty
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/PooledConnection.html">PooledConnection</a>,
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Communicator.html">Communicator</a> and
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Client.html">Client</a> beans.</p>
<p>Arguments <tt>idleTime</tt> and <tt>timeUnit</tt> must be given.</p>
<p>Argument <tt>idleTime</tt> is optional, and defaults to the value of the <tt>connect.api.close-idle-connections.idle-time</tt> <a href="properties.html">property</a>.
It can be specified <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.conversion.durations">as a duration in the Spring Boot supported format</a>.</p>
<p>HTTP endpoint examples:</p>
<pre>curl -X DELETE 'http://&lt;host&gt;/actuator/idleConnectSdkConnections?idleTime=20&amp;timeUnit=SECONDS'</pre>
<pre>curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections
curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections?idleTime=10000
curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections?idleTime=10s</pre>

<h4>closeIdleConnectionsForBean</h4>
<p>Closes idle connections for a specific
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/PooledConnection.html">PooledConnection</a>,
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Communicator.html">Communicator</a> and
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Communicator.html">Communicator</a> or
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Client.html">Client</a> bean.</p>
<p>Arguments <tt>idleTime</tt> and <tt>timeUnit</tt> must be given.</p>
<p>Argument <tt>idleTime</tt> is optional, and defaults to the value of the <tt>connect.api.close-idle-connections.idle-time</tt> <a href="properties.html">property</a>.
It can be specified <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.conversion.durations">as a duration in the Spring Boot supported format</a>.</p>
<p>HTTP endpoint examples:</p>
<pre>curl -X DELETE 'http://&lt;host&gt;/actuator/idleConnectSdkConnections/myBean?idleTime=20&amp;timeUnit=SECONDS'</pre>
<pre>curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections/myBean
curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections/myBean?idleTime=10000
curl -X DELETE http://&lt;host&gt;/actuator/idleConnectSdkConnections/myBean?idleTime=10s</pre>

<h4>closeExpiredConnections</h4>
<p>Closes expired connections for all available
Expand All @@ -94,7 +100,7 @@ curl -X POST http://&lt;host&gt;/actuator/connectSdkLogging/myBean -H Content-Ty
<h4>closeExpiredConnectionsForBean</h4>
<p>Closes expired connections for a specific
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/PooledConnection.html">PooledConnection</a>,
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Communicator.html">Communicator</a> and
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Communicator.html">Communicator</a> or
<a href="https://ingenico-epayments.github.io/connect-sdk-java/apidocs/latest/com/ingenico/connect/gateway/sdk/java/Client.html">Client</a> bean.</p>
<p>HTTP endpoint example:</p>
<pre>curl -X DELETE http://&lt;host&gt;/actuator/expiredConnectSdkConnections/myBean</pre>
Expand All @@ -109,8 +115,7 @@ curl -X POST http://&lt;host&gt;/actuator/connectSdkLogging/myBean -H Content-Ty
<h4>setApiKey</h4>
<p>Changes the API key id, secret API key and authorization type (defaults to <tt>V1HMAC</tt>) of the auto-configured <tt>Authenticator</tt>.</p>
<p>HTTP endpoint example:</p>
<pre>curl -X POST http://&lt;host&gt;/actuator/connectSdkApiKey -H Content-Type:application/json
curl -X POST http://&lt;host&gt;/actuator/connectSdkApiKey -H Content-Type:application/json -d '{"apiKeyId": "myApiKeyId", "secretApiKey": "mySecretKeyId"}'
<pre>curl -X POST http://&lt;host&gt;/actuator/connectSdkApiKey -H Content-Type:application/json -d '{"apiKeyId": "myApiKeyId", "secretApiKey": "mySecretKeyId"}'
curl -X POST http://&lt;host&gt;/actuator/connectSdkApiKey -H Content-Type:application/json -d '{"apiKeyId": "myApiKeyId", "secretApiKey": "mySecretKeyId", "authorizationType": "V1HMAC"}'</pre>
</div>
</body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,37 +193,78 @@ void testListCloseableBeans() {
@Nested
class CloseIdleConnections {

@Test
@SuppressWarnings("resource")
void testForAllBeans() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections?idleTime=20&timeUnit=SECONDS"))
.build();
@Nested
class ForAllBeans {

ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);
@Test
@SuppressWarnings("resource")
void testWithDefaultIdleTime() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections"))
.build();

assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);

// 3 times: one through the client, once through the communicator, once through the connection itself
verify(connection, times(3)).closeIdleConnections(20, TimeUnit.SECONDS);
assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());

// 3 times: one through the client, once through the communicator, once through the connection itself
verify(connection, times(3)).closeIdleConnections(20_000, TimeUnit.MILLISECONDS);
}

@Test
@SuppressWarnings("resource")
void testWithExplicitIdleTime() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections?idleTime=10s"))
.build();

ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);

assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());

// 3 times: one through the client, once through the communicator, once through the connection itself
verify(connection, times(3)).closeIdleConnections(10_000, TimeUnit.MILLISECONDS);
}
}

@Test
@SuppressWarnings("resource")
void testForSpecificBean() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections/mockConnection?idleTime=20&timeUnit=SECONDS"))
.build();
@Nested
class ForSpecificBean {

ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);
@Test
@SuppressWarnings("resource")
void testWithDefaultIdleTime() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections/mockConnection"))
.build();

assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);

assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());

verify(connection).closeIdleConnections(20_000, TimeUnit.MILLISECONDS);
}

@Test
@SuppressWarnings("resource")
void testWithExplicitIdleTime() {
RequestEntity<Void> request = RequestEntity
.delete(getActuatorBaseURI().resolve("idleConnectSdkConnections/mockConnection?idleTime=10s"))
.build();

verify(connection).closeIdleConnections(20, TimeUnit.SECONDS);
ResponseEntity<Void> response = restTemplateBuilder
.build()
.exchange(request, Void.class);

assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());

verify(connection).closeIdleConnections(10_000, TimeUnit.MILLISECONDS);
}
}
}

Expand Down
Loading

0 comments on commit 3a3c847

Please sign in to comment.