-
Notifications
You must be signed in to change notification settings - Fork 28
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
Create new connection provider during IP failovers #117
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,8 @@ class ConnectionProvider(props: Properties) { | |
@volatile | ||
private var cachedIpWithExpiration: Option[CachedIpWithExpiration] = None | ||
|
||
private val pool: Pool = new Pool(getIP) | ||
@volatile | ||
private var pool: Pool = new Pool(getIP) | ||
|
||
// Intended to be used only for tests. This mocks an IP failover every time a connection is retreived | ||
private val causeFailoverEveryConnection = props.getProperty("causeFailoverEveryConnection") == "true" | ||
|
@@ -111,7 +112,28 @@ class ConnectionProvider(props: Properties) { | |
val newIP: String = getIP | ||
if (hasIpAddressChanged(pool, newIP)) { | ||
// A failover has occurred, so we evict connections softly. New connectons look up the new IP address | ||
pool.connectionProvider.map(_.getDataSource().getHikariPoolMXBean().softEvictConnections()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a theory that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly we are running into brettwooldridge/HikariCP#1836 ?
I don't thilnk that is right. Nothing in the documentation indicates that behavior. However, brettwooldridge/HikariCP#228 does recommend replacing the entire pool, so I guess that might be a better approach. |
||
logger.info(s"IP Address has changed for ${jdbcURL}: ${pool.ip} -> ${newIP}. Attempt replacing pool...") | ||
val optionalOldPool = synchronized { | ||
val oldPool = pool | ||
// check if another thread updated the pool | ||
if (hasIpAddressChanged(pool, newIP)) { | ||
logger.info(s"Replacing pool for ${jdbcURL}...") | ||
pool = new Pool(newIP) | ||
Some(oldPool) | ||
} else { | ||
// already up to date | ||
logger.info(s"Pool already replaced for ${jdbcURL}") | ||
None | ||
} | ||
} | ||
|
||
// Clean up old pool so we don't leak connections to the old server | ||
optionalOldPool.foreach { oldPool => | ||
oldPool.connectionProvider.foreach { provider => | ||
logger.info(s"Closing DB connection pool for ${jdbcURL} for failover (${oldPool.ip} -> ${pool.ip})") | ||
provider.shutdown() | ||
} | ||
} | ||
} | ||
} | ||
pool.connectionProvider.get.getConnection | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unnecessary since we only access it from within a synchronized block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We read from this value outside the synchronized block on lines 113, 115, and 139, for example to get a connection:
Thus volatile will make sure the
pool
is assigned completely before we attempt to get connections from it