ch.sourcemotion.vertx.redis.client.heimdall.impl.reconnect.RedisReconnectProcess.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vertx-redis-client-heimdall Show documentation
Show all versions of vertx-redis-client-heimdall Show documentation
Redis client based on the official one https://vertx.io/docs/vertx-redis-client/java/. This client will provide some additional features like reconnect capabilities, Event bus events on reconnecting related activities.
The newest version!
package ch.sourcemotion.vertx.redis.client.heimdall.impl.reconnect
import ch.sourcemotion.vertx.redis.client.heimdall.RedisHeimdallException
import ch.sourcemotion.vertx.redis.client.heimdall.RedisHeimdallException.Reason
import ch.sourcemotion.vertx.redis.client.heimdall.RedisHeimdallOptions
import io.vertx.core.*
import io.vertx.core.logging.LoggerFactory
import io.vertx.redis.client.Command
import io.vertx.redis.client.Redis
import io.vertx.redis.client.RedisConnection
import io.vertx.redis.client.Request
internal interface RedisReconnectProcess {
fun startReconnectProcess(cause: Throwable): Future
}
internal abstract class AbstractRedisReconnectProcess(
protected val options: RedisHeimdallOptions,
) : RedisReconnectProcess
internal class NoopRedisReconnectProcess(options: RedisHeimdallOptions) : AbstractRedisReconnectProcess(options) {
override fun startReconnectProcess(cause: Throwable): Future {
return Future.failedFuture(
RedisHeimdallException(
Reason.RECONNECT_DISABLED,
"Extended Redis client that's configured for server(s)" +
" ${options.endpointsToString()} is not configured for retries"
)
)
}
}
internal class DefaultRedisReconnectProcess(
private val vertx: Vertx,
options: RedisHeimdallOptions,
private val maxReconnectAttempts: Int = options.maxReconnectAttempts,
private val reconnectInterval: Long = options.reconnectInterval
) : AbstractRedisReconnectProcess(options) {
companion object {
private val logger = LoggerFactory.getLogger(DefaultRedisReconnectProcess::class.java)
}
override fun startReconnectProcess(cause: Throwable): Future {
val promise = Promise.promise()
reconnect(promise)
return promise.future()
}
private fun reconnect(promise: Promise, previousAttempts: Int = 0) {
if (maxReconnectAttempts in 1..previousAttempts) {
logger.warn("Max attempts to reconnect to Redis server(s) ${options.endpointsToString()} reached. Will skip.")
promise.fail(
RedisHeimdallException(
Reason.MAX_ATTEMPTS_REACHED,
message = "Max number of reconnect attempts \"$maxReconnectAttempts\" to Redis server(s) ${options.endpointsToString()}"
)
)
} else {
val client = Redis.createClient(vertx, options.redisOptions)
client.connect()
.onSuccess { connection ->
connection.verifyConnection { verification ->
connection.close()
if (verification.succeeded()) {
logger.info("Redis client reconnected to server(s) ${options.endpointsToString()}")
promise.complete(client)
} else {
scheduleReattempt(promise, previousAttempts)
}
}
}.onFailure { scheduleReattempt(promise, previousAttempts) }
}
}
private fun scheduleReattempt(promise: Promise, previousAttempts: Int) {
logger.debug(
"Unable to reconnect to Redis server(s) ${options.endpointsToString()}. " +
"Will retry in $reconnectInterval Milliseconds"
)
vertx.setTimer(reconnectInterval) {
reconnect(promise, previousAttempts + 1)
}
}
private fun RedisConnection.verifyConnection(handler: Handler>) {
send(Request.cmd(Command.PING)) {
if (it.succeeded() && it.result().toString() == "PONG") {
handler.handle(Future.succeededFuture())
} else {
handler.handle(Future.failedFuture(it.cause()))
}
}
}
}