Pooling connection managers to implement graceful and immediate shut down

This commit is contained in:
Oleg Kalnichevski 2018-06-16 11:26:35 +02:00
parent 60571ae8fa
commit 6570228118
6 changed files with 41 additions and 36 deletions

View File

@ -152,8 +152,13 @@ public BasicHttpClientConnectionManager() {
@Override @Override
public void close() { public void close() {
shutdown(ShutdownType.GRACEFUL);
}
@Override
public void shutdown(final ShutdownType shutdownType) {
if (this.closed.compareAndSet(false, true)) { if (this.closed.compareAndSet(false, true)) {
shutdownConnection(); closeConnection(shutdownType);
} }
} }
@ -200,24 +205,10 @@ public boolean cancel() {
}; };
} }
private synchronized void closeConnection() { private synchronized void closeConnection(final ShutdownType shutdownType) {
if (this.conn != null) { if (this.conn != null) {
this.log.debug("Closing connection"); this.log.debug("Shutting down connection " + shutdownType);
try { this.conn.shutdown(shutdownType);
this.conn.close();
} catch (final IOException iox) {
if (this.log.isDebugEnabled()) {
this.log.debug("I/O exception closing connection", iox);
}
}
this.conn = null;
}
}
private synchronized void shutdownConnection() {
if (this.conn != null) {
this.log.debug("Shutting down connection");
this.conn.shutdown(ShutdownType.GRACEFUL);
this.conn = null; this.conn = null;
} }
} }
@ -227,7 +218,7 @@ private void checkExpiry() {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {
this.log.debug("Connection expired @ " + new Date(this.expiry)); this.log.debug("Connection expired @ " + new Date(this.expiry));
} }
closeConnection(); closeConnection(ShutdownType.GRACEFUL);
} }
} }
@ -238,7 +229,7 @@ synchronized ManagedHttpClientConnection getConnection(final HttpRoute route, fi
} }
Asserts.check(!this.leased, "Connection is still allocated"); Asserts.check(!this.leased, "Connection is still allocated");
if (!LangUtils.equals(this.route, route) || !LangUtils.equals(this.state, state)) { if (!LangUtils.equals(this.route, route) || !LangUtils.equals(this.state, state)) {
closeConnection(); closeConnection(ShutdownType.GRACEFUL);
} }
this.route = route; this.route = route;
this.state = state; this.state = state;
@ -362,7 +353,7 @@ public synchronized void closeIdle(final long idletime, final TimeUnit tunit) {
} }
final long deadline = System.currentTimeMillis() - time; final long deadline = System.currentTimeMillis() - time;
if (this.updated <= deadline) { if (this.updated <= deadline) {
closeConnection(); closeConnection(ShutdownType.GRACEFUL);
} }
} }
} }

View File

@ -222,10 +222,17 @@ protected PoolingHttpClientConnectionManager(
@Override @Override
public void close() { public void close() {
shutdown(ShutdownType.GRACEFUL);
}
@Override
public void shutdown(final ShutdownType shutdownType) {
if (this.closed.compareAndSet(false, true)) { if (this.closed.compareAndSet(false, true)) {
this.log.debug("Connection manager is shutting down"); if (this.log.isDebugEnabled()) {
this.pool.shutdown(ShutdownType.GRACEFUL); this.log.debug("Shutdown connection pool " + shutdownType);
this.log.debug("Connection manager shut down"); }
this.pool.shutdown(shutdownType);
this.log.debug("Connection pool shut down");
} }
} }

View File

@ -188,10 +188,17 @@ protected PoolingAsyncClientConnectionManager(
@Override @Override
public void close() { public void close() {
if (closed.compareAndSet(false, true)) { shutdown(ShutdownType.GRACEFUL);
log.debug("Connection manager is shutting down"); }
pool.shutdown(ShutdownType.GRACEFUL);
log.debug("Connection manager shut down"); @Override
public void shutdown(final ShutdownType shutdownType) {
if (this.closed.compareAndSet(false, true)) {
if (this.log.isDebugEnabled()) {
this.log.debug("Shutdown connection pool " + shutdownType);
}
this.pool.shutdown(shutdownType);
this.log.debug("Connection pool shut down");
} }
} }

View File

@ -26,11 +26,11 @@
*/ */
package org.apache.hc.client5.http.io; package org.apache.hc.client5.http.io;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.io.GracefullyCloseable;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
@ -48,7 +48,7 @@
* *
* @since 4.3 * @since 4.3
*/ */
public interface HttpClientConnectionManager extends Closeable { public interface HttpClientConnectionManager extends GracefullyCloseable {
/** /**
* Returns a {@link LeaseRequest} object which can be used to obtain * Returns a {@link LeaseRequest} object which can be used to obtain

View File

@ -26,12 +26,12 @@
*/ */
package org.apache.hc.client5.http.nio; package org.apache.hc.client5.http.nio;
import java.io.Closeable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.io.GracefullyCloseable;
import org.apache.hc.core5.reactor.ConnectionInitiator; import org.apache.hc.core5.reactor.ConnectionInitiator;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
@ -50,7 +50,7 @@
* *
* @since 5.0 * @since 5.0
*/ */
public interface AsyncClientConnectionManager extends Closeable { public interface AsyncClientConnectionManager extends GracefullyCloseable {
/** /**
* Returns a {@link Future} object which can be used to obtain * Returns a {@link Future} object which can be used to obtain

View File

@ -192,7 +192,7 @@ public void testLeaseDifferentRoute() throws Exception {
Assert.assertNotNull(conn2); Assert.assertNotNull(conn2);
Assert.assertFalse(conn2.isConnected()); Assert.assertFalse(conn2.isConnected());
Mockito.verify(conn).close(); Mockito.verify(conn).shutdown(ShutdownType.GRACEFUL);
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any()); Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
} }
@ -223,7 +223,7 @@ public void testLeaseExpired() throws Exception {
Assert.assertNotNull(conn2); Assert.assertNotNull(conn2);
Assert.assertFalse(conn2.isConnected()); Assert.assertFalse(conn2.isConnected());
Mockito.verify(conn).close(); Mockito.verify(conn).shutdown(ShutdownType.GRACEFUL);
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any()); Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
} }
@ -298,7 +298,7 @@ public void testCloseExpired() throws Exception {
mgr.closeExpired(); mgr.closeExpired();
Mockito.verify(conn).close(); Mockito.verify(conn).shutdown(ShutdownType.GRACEFUL);
} }
@Test @Test
@ -325,7 +325,7 @@ public void testCloseIdle() throws Exception {
mgr.closeIdle(50, TimeUnit.MILLISECONDS); mgr.closeIdle(50, TimeUnit.MILLISECONDS);
Mockito.verify(conn).close(); Mockito.verify(conn).shutdown(ShutdownType.GRACEFUL);
} }
@Test(expected=IllegalStateException.class) @Test(expected=IllegalStateException.class)