Skip to content

Commit

Permalink
feat: Added a maxIdleTime parameter to the connection cache (Defaults…
Browse files Browse the repository at this point in the history
… to 5 minutes)
  • Loading branch information
chrisdutz committed Jul 5, 2024
1 parent f39cc44 commit dc4f02c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
Expand All @@ -43,6 +42,7 @@ public class CachedPlcConnectionManager implements PlcConnectionManager, AutoClo
private final PlcConnectionManager connectionManager;
private final Duration maxLeaseTime;
private final Duration maxWaitTime;
private final Duration maxIdleTime;

private final Map<String, ConnectionContainer> connectionContainers;

Expand All @@ -56,10 +56,11 @@ public static Builder getBuilder(PlcConnectionManager connectionManager) {
return new Builder(connectionManager);
}

public CachedPlcConnectionManager(PlcConnectionManager connectionManager, Duration maxLeaseTime, Duration maxWaitTime) {
public CachedPlcConnectionManager(PlcConnectionManager connectionManager, Duration maxLeaseTime, Duration maxWaitTime, Duration maxIdleTime) {
this.connectionManager = connectionManager;
this.maxLeaseTime = maxLeaseTime;
this.maxWaitTime = maxWaitTime;
this.maxIdleTime = maxIdleTime;
this.connectionContainers = new HashMap<>();
}

Expand Down Expand Up @@ -96,7 +97,11 @@ public PlcConnection getConnection(String url) throws PlcConnectionException {
LOG.debug("Creating new connection");

// Crate a connection container to manage handling this connection
connectionContainer = new ConnectionContainer(connectionManager, url, maxLeaseTime);
connectionContainer = new ConnectionContainer(connectionManager, url, maxLeaseTime, maxIdleTime,
closeConnection -> {
removeCachedConnection(closeConnection);
return null;
});
connectionContainers.put(url, connectionContainer);
} else {
LOG.debug("Reusing exising connection");
Expand Down Expand Up @@ -132,15 +137,18 @@ public static class Builder {
private final PlcConnectionManager connectionManager;
private Duration maxLeaseTime;
private Duration maxWaitTime;
private Duration maxIdleTime;

public Builder(PlcConnectionManager connectionManager) {
this.connectionManager = connectionManager;
this.maxLeaseTime = Duration.ofSeconds(4);
this.maxWaitTime = Duration.ofSeconds(20);
this.maxIdleTime = Duration.ofMinutes(5);
}

public CachedPlcConnectionManager build() {
return new CachedPlcConnectionManager(this.connectionManager, this.maxLeaseTime, this.maxWaitTime);
return new CachedPlcConnectionManager(
this.connectionManager, this.maxLeaseTime, this.maxWaitTime, this.maxIdleTime);
}

public CachedPlcConnectionManager.Builder withMaxLeaseTime(Duration maxLeaseTime) {
Expand All @@ -152,6 +160,11 @@ public CachedPlcConnectionManager.Builder withMaxWaitTime(Duration maxWaitTime)
this.maxWaitTime = maxWaitTime;
return this;
}

public CachedPlcConnectionManager.Builder withMaxIdleTime(Duration maxIdleTime) {
this.maxIdleTime = maxIdleTime;
return this;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,32 @@
import java.time.Duration;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.Function;

class ConnectionContainer {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionContainer.class);
private final PlcConnectionManager connectionManager;
private final String connectionUrl;
private final Duration maxLeaseTime;
private final Duration maxIdleTime;
private final Function<String, Void> closeConnectionHandler;
private final Queue<CompletableFuture<PlcConnection>> queue;

private PlcConnection connection;
private LeasedPlcConnection leasedConnection;

public ConnectionContainer(PlcConnectionManager connectionManager, String connectionUrl, Duration maxLeaseTime) {
public ConnectionContainer(PlcConnectionManager connectionManager, String connectionUrl,
Duration maxLeaseTime, Duration maxIdleTime,
Function<String, Void> closeConnectionHandler) {
this.connectionManager = connectionManager;
this.connectionUrl = connectionUrl;
this.maxLeaseTime = maxLeaseTime;
this.maxIdleTime = maxIdleTime;
this.closeConnectionHandler = closeConnectionHandler;
this.queue = new LinkedList<>();
this.connection = null;
this.leasedConnection = null;
Expand Down Expand Up @@ -128,6 +137,15 @@ public synchronized void returnConnection(LeasedPlcConnection returnedLeasedConn
// If the queue is empty, simply return.
if(queue.isEmpty()) {
leasedConnection = null;

// Start a timer to invalidate this connection if it's idle for too long.
Timer idleTimer = new Timer();
idleTimer.schedule(new TimerTask() {
@Override
public void run() {
closeConnectionHandler.apply(connectionUrl);
}
}, maxIdleTime.toMillis());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,20 @@ public void testClosingConnectionCache() throws Exception {
}
}

@Test
public void testCloseAfterIdleTime() throws Exception {
PlcConnectionManager mockConnectionManager = Mockito.mock(PlcConnectionManager.class);
Mockito.when(mockConnectionManager.getConnection("test")).thenReturn(Mockito.mock(PlcConnection.class));
CachedPlcConnectionManager connectionManager = CachedPlcConnectionManager.getBuilder(mockConnectionManager).withMaxWaitTime(Duration.ofMillis(50)).withMaxIdleTime(Duration.ofMillis(10)).build();

// Get a connection and directly return it.
PlcConnection connection = connectionManager.getConnection("test");
connection.close();

// Wait for longer than the max idle time.
Thread.sleep(20);

Assertions.assertEquals(0, connectionManager.getCachedConnections().size());
}

}

0 comments on commit dc4f02c

Please sign in to comment.