Skip to content

Commit 3e28e75

Browse files
committed
Add configuration option for RedisConnectionPool lease timeout
Motivation: With RedisConnectionPool a timeout is provided to prevent infinite loops of retrying connections, but right now it is hardcoded to 60 seconds. Users of downstream projects such as Vapor are noticing a "regression" of sorts, as previously EventLoopFutures would fail immediately if a connection was not made available. Modifications: - Add: `connectionRetryTimeout` parameter to `RedisConnectionPool` initializer that still defaults to 60 seconds - Change: RedisConnectionPool to use the new parameter if available to offset a deadline from "now" Result: Users can now configure the connection pool to fail immediately if connections are not available.
1 parent e858c0a commit 3e28e75

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

Sources/RediStack/RedisConnectionPool.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class RedisConnectionPool {
4545
/// This needs to be a var because we reuse the same connection
4646
private var pubsubConnection: RedisConnection?
4747

48+
private let connectionRetryTimeout: TimeAmount?
4849
private let connectionPassword: String?
4950
private let connectionSystemContext: Logger
5051
private let poolSystemContext: Context
@@ -69,6 +70,8 @@ public class RedisConnectionPool {
6970
/// factor, each connection attempt will be delayed by this amount times the previous delay.
7071
/// - initialConnectionBackoffDelay: If a TCP connection attempt fails, this is the first backoff value on the reconnection attempt.
7172
/// Subsequent backoffs are computed by compounding this value by `connectionBackoffFactor`.
73+
/// - connectionRetryTimeout: The max time to wait for a connection to be available before failing a particular command or connection operation.
74+
/// The default is 60 seconds.
7275
public init(
7376
serverConnectionAddresses: [SocketAddress],
7477
loop: EventLoop,
@@ -79,11 +82,13 @@ public class RedisConnectionPool {
7982
connectionTCPClient: ClientBootstrap? = nil,
8083
poolLogger: Logger = .redisBaseConnectionPoolLogger,
8184
connectionBackoffFactor: Float32 = 2,
82-
initialConnectionBackoffDelay: TimeAmount = .milliseconds(100)
85+
initialConnectionBackoffDelay: TimeAmount = .milliseconds(100),
86+
connectionRetryTimeout: TimeAmount? = .seconds(60)
8387
) {
8488
self.loop = loop
8589
self.serverConnectionAddresses = ConnectionAddresses(initialAddresses: serverConnectionAddresses)
8690
self.connectionPassword = connectionPassword
91+
self.connectionRetryTimeout = connectionRetryTimeout
8792

8893
// mix of terminology here with the loggers
8994
// as we're being "forward thinking" in terms of the 'baggage context' future type
@@ -387,9 +392,11 @@ extension RedisConnectionPool: RedisClientWithUserContext {
387392
let logger = self.prepareLoggerForUse(context)
388393

389394
guard let connection = preferredConnection else {
390-
// For now we have to default the deadline.
391-
// For maximum compatibility with the existing implementation, we use a fairly-long timeout: one minute.
392-
return pool.leaseConnection(deadline: .now() + .seconds(60), logger: logger)
395+
return pool
396+
.leaseConnection(
397+
deadline: self.connectionRetryTimeout.map({ .now() + $0 }) ?? .now(),
398+
logger: logger
399+
)
393400
.flatMap { operation($0, pool.returnConnection(_:logger:), logger) }
394401
}
395402

0 commit comments

Comments
 (0)