Skip to content

Configurable test-on-borrow for pooled connections #297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 2, 2017

Conversation

lutovich
Copy link
Contributor

Connections are pooled for both direct and routing driver. Each acquired session contains a socket connection which was acquired from the pool. It is possible for an idle pooled connection to become invalid while just resting in the pool. This could happen when connection is terminated after some timeout by a load balancer or some other network facility.

This PR introduces a configurable connection liveness check timeout. So freshly acquired connection, that has been idle in the pool for more than configurable timeout, will be validated by sending a RESET message. If it appears to be broken acquisition will retry until a valid connection is found.

Connections are pooled for both direct and routing driver. Each acquired
session contains a socket connection which was acquired from the pool.
It is possible for an idle pooled connection to become invalid while just
resting in the pool. This could happen when connection is terminated after
some timeout by a load balancer or some other network facility.

This commit introduces a configurable connection liveness check timeout.
So freshly acquired connection, that has been idle in the pool for more
than configurable timeout, will be validated by sending a RESET message.
If it appears to be broken acquisition will retry until a valid
connection is found.
@lutovich lutovich force-pushed the 1.1-idle-connection-refresh branch from b3229dc to d840e07 Compare January 2, 2017 10:55
*/
@Deprecated
public long idleTimeBeforeConnectionTest()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to keep this old name. Pls pick a good name that better describes this config instead.

*/
@Deprecated
public ConfigBuilder withSessionLivenessCheckTimeout( long timeout )
public ConfigBuilder withSessionLivenessCheckTimeout( long value, TimeUnit unit )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, the name should be consistent with the field/method name in Config


int acquisitionAttempt = 1;
PooledConnection connection = connectionQueue.acquire( supplier );
while ( !canBeAcquired( connection, acquisitionAttempt ) )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting to test queue.isEmpty() instead. And the while loop would be changed to something like

boolean done = false;
while(!done)
{
  if(connectionQueue.isEmpty())
  {
    done = true; // let `queue.acquire` for queue size + 1 times 
  }
  PooledConnection conn = connectionQueue.acquire(supplier);
  if(isHealthyConnection(conn))
  {
    return conn;
  }
}
// `isHealthyConnection` will not throw exception, so this is a final protection of NPE
throw new ClientException("Failed to establish connection with the server or some other better error message"); 


private boolean isHealthyConneciton(PooledConnection conn)
{
  if ( poolSettings.idleTimeBeforeConnectionTestConfigured() && hasBeenIdleForTooLong(conn) )
  {
    return connectionValidator.isConnected( connection );
  }
  return true;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed code to track when connection was created and then return it. So it'll retry until new connection is created and then return it to the user.

}

@Override
public void close()
private boolean canBeAcquired( PooledConnection connection, int acquisitionAttempt )
Copy link
Contributor

@zhenlineo zhenlineo Jan 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed if we have isHealthyConneciton (see the previous comment)

@@ -68,26 +71,41 @@ public SocketConnectionPool( PoolSettings poolSettings, Connector connector, Clo
public Connection acquire( final BoltServerAddress address )
{
assertNotClosed();
BlockingPooledConnectionQueue connectionQueue = pool( address );
PooledConnection connection = acquireConnection( address, connectionQueue );
Copy link
Contributor

@zhenlineo zhenlineo Jan 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR but wonder if it would be better API if we let the pooled connection to hold a reference to connecitonValidator and let the pooledConnection to provide methods to test isConnected and isReusable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could also simplify things around these suppliers and consumers. Let's think about it.

long idleTimeBeforeConnectionTestMillis = unit.toMillis( value );
if ( idleTimeBeforeConnectionTestMillis <= 0 )
{
throw new IllegalArgumentException( String.format(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not let the user to set to -1 (default value)?

`SocketConnectionPool` can test connections during acquisition. This is done
when they have been idle in the pool for too long. This commit makes it retry
until new connection is created instead of `maxPoolSize`times.
Renamed `withSessionLivenessCheckTimeout` to `withConnectionLivenessCheckTimeout`
because all other methods refer to connections instead of sessions and are
actually settings for the connection pool and not session pool.
So feature can be easier turned on and off by users. Zero timeout means always
do test-on-borrow, negative timeout means never to test-on-borrow.
@lutovich
Copy link
Contributor Author

lutovich commented Jan 2, 2017

@zhenlineo comments addressed

Copy link
Contributor

@zhenlineo zhenlineo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM besides a minor doc change suggestion.

}

/**
* Pooled sessions that have been idle in the pool for longer than this timeout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls use Pooled connections instead as pooled sessions is a wrong terminology used before.

@@ -116,17 +123,14 @@ public int maxIdleConnectionPoolSize()
}

/**
* Pooled connections that have been unused for longer than this timeout will be tested before they are
* used again, to ensure they are still live.
* Pooled sessions that have been idle in the pool for longer than this timeout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pooled "connections"

Changed "session" to "connection" because config should only contain settings
for the connection pool. There is no such thing as session pool.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants