HTTPCLIENT-2318 - Enhance PoolingHttpClientConnectionManager with isShutdown State Check.
This commit introduces an `isShutdown` method to the `PoolingHttpClientConnectionManager` class, providing a thread-safe way to check whether the connection manager has been closed. The addition leverages an existing `AtomicBoolean` closed flag to ensure that the shutdown state can be queried reliably in concurrent environments.
This commit is contained in:
parent
8a7f707a61
commit
407b9152cc
|
@ -711,8 +711,9 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
||||||
*
|
*
|
||||||
* @return {@code true} if the connection manager has been shut down and is closed, otherwise
|
* @return {@code true} if the connection manager has been shut down and is closed, otherwise
|
||||||
* return {@code false}.
|
* return {@code false}.
|
||||||
|
* @since 5.4
|
||||||
*/
|
*/
|
||||||
boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return this.closed.get();
|
return this.closed.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -423,6 +423,11 @@ public class PoolingHttpClientConnectionManager
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("{} releasing endpoint", ConnPoolSupport.getId(endpoint));
|
LOG.debug("{} releasing endpoint", ConnPoolSupport.getId(endpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
final ManagedHttpClientConnection conn = entry.getConnection();
|
||||||
if (conn != null && keepAlive == null) {
|
if (conn != null && keepAlive == null) {
|
||||||
conn.close(CloseMode.GRACEFUL);
|
conn.close(CloseMode.GRACEFUL);
|
||||||
|
@ -522,11 +527,17 @@ public class PoolingHttpClientConnectionManager
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Closing connections idle longer than {}", idleTime);
|
LOG.debug("Closing connections idle longer than {}", idleTime);
|
||||||
}
|
}
|
||||||
|
if (isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.pool.closeIdle(idleTime);
|
this.pool.closeIdle(idleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeExpired() {
|
public void closeExpired() {
|
||||||
|
if (isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
LOG.debug("Closing expired connections");
|
LOG.debug("Closing expired connections");
|
||||||
this.pool.closeExpired();
|
this.pool.closeExpired();
|
||||||
}
|
}
|
||||||
|
@ -796,4 +807,17 @@ public class PoolingHttpClientConnectionManager
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that can be called to determine whether the connection manager has been shut down and
|
||||||
|
* is closed or not.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the connection manager has been shut down and is closed, otherwise
|
||||||
|
* return {@code false}.
|
||||||
|
* @since 5.4
|
||||||
|
*/
|
||||||
|
public boolean isClosed() {
|
||||||
|
return this.closed.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,6 +394,9 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("{} releasing endpoint", ConnPoolSupport.getId(endpoint));
|
LOG.debug("{} releasing endpoint", ConnPoolSupport.getId(endpoint));
|
||||||
}
|
}
|
||||||
|
if (this.isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final ManagedAsyncClientConnection connection = entry.getConnection();
|
final ManagedAsyncClientConnection connection = entry.getConnection();
|
||||||
boolean reusable = connection != null && connection.isOpen();
|
boolean reusable = connection != null && connection.isOpen();
|
||||||
try {
|
try {
|
||||||
|
@ -575,11 +578,17 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeIdle(final TimeValue idletime) {
|
public void closeIdle(final TimeValue idletime) {
|
||||||
|
if (isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
pool.closeIdle(idletime);
|
pool.closeIdle(idletime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeExpired() {
|
public void closeExpired() {
|
||||||
|
if (isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
pool.closeExpired();
|
pool.closeExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,8 +782,9 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
|
||||||
*
|
*
|
||||||
* @return {@code true} if the connection manager has been shut down and is closed, otherwise
|
* @return {@code true} if the connection manager has been shut down and is closed, otherwise
|
||||||
* return {@code false}.
|
* return {@code false}.
|
||||||
|
* @since 5.4
|
||||||
*/
|
*/
|
||||||
boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return this.closed.get();
|
return this.closed.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ package org.apache.hc.client5.http.impl.io;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
@ -351,4 +353,56 @@ public class TestPoolingHttpClientConnectionManager {
|
||||||
socket, "somehost", 443, tlsConfig, context);
|
socket, "somehost", 443, tlsConfig, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsShutdownInitially() {
|
||||||
|
Assertions.assertFalse(mgr.isClosed(), "Connection manager should not be shutdown initially.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShutdownIdempotency() {
|
||||||
|
mgr.close();
|
||||||
|
Assertions.assertTrue(mgr.isClosed(), "Connection manager should remain shutdown after the first call to shutdown.");
|
||||||
|
mgr.close(); // Second call to shutdown
|
||||||
|
Assertions.assertTrue(mgr.isClosed(), "Connection manager should still be shutdown after subsequent calls to shutdown.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLeaseAfterShutdown() {
|
||||||
|
mgr.close();
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
// Attempt to lease a connection after shutdown
|
||||||
|
mgr.lease("some-id", new HttpRoute(new HttpHost("localhost")), null);
|
||||||
|
}, "Attempting to lease a connection after shutdown should throw an exception.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsShutdown() {
|
||||||
|
// Setup phase
|
||||||
|
Mockito.when(pool.isShutdown()).thenReturn(false, true); // Simulate changing states
|
||||||
|
|
||||||
|
// Execution phase: Initially, the manager should not be shutdown
|
||||||
|
Assertions.assertFalse(mgr.isClosed(), "Connection manager should not be shutdown initially.");
|
||||||
|
|
||||||
|
// Simulate shutting down the manager
|
||||||
|
mgr.close();
|
||||||
|
|
||||||
|
// Verification phase: Now, the manager should be reported as shutdown
|
||||||
|
Assertions.assertTrue(mgr.isClosed(), "Connection manager should be shutdown after close() is called.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConcurrentShutdown() throws InterruptedException {
|
||||||
|
final ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||||
|
// Submit two shutdown tasks to be run in parallel, explicitly calling close() with no arguments
|
||||||
|
executor.submit(() -> mgr.close());
|
||||||
|
executor.submit(() -> mgr.close());
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(1, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
Assertions.assertTrue(mgr.isClosed(), "Connection manager should be shutdown after concurrent calls to shutdown.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue