Skip to content

Commit 97dc6dd

Browse files
authored
Split up Configuration file into two: RedisConnectionPool & RedisConnection (#78)
1 parent 8843065 commit 97dc6dd

File tree

2 files changed

+193
-179
lines changed

2 files changed

+193
-179
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the RediStack open source project
4+
//
5+
// Copyright (c) 2020-2023 RediStack project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of RediStack project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
import NIOPosix
17+
import Logging
18+
19+
extension RedisConnectionPool {
20+
/// A configuration object for creating Redis connections with a connection pool.
21+
/// - Warning: This type has **reference** semantics due to the `NIO.ClientBootstrap` reference.
22+
public struct ConnectionFactoryConfiguration {
23+
// this needs to be var so it can be updated by the pool with the pool id
24+
/// The logger prototype that will be used by connections by default when generating logs.
25+
public internal(set) var connectionDefaultLogger: Logger
26+
/// The username used to authenticate connections.
27+
/// - Warning: This property should only be provided if you are running against Redis 6 or higher.
28+
public let connectionUsername: String?
29+
/// The password used to authenticate connections.
30+
public let connectionPassword: String?
31+
/// The initial database index that connections should use.
32+
public let connectionInitialDatabase: Int?
33+
/// The pre-configured TCP client for connections to use.
34+
public let tcpClient: ClientBootstrap?
35+
36+
/// Creates a new connection factory configuration with the provided options.
37+
/// - Parameters:
38+
/// - connectionInitialDatabase: The optional database index to initially connect to. The default is `nil`.
39+
/// Redis by default opens connections against index `0`, so only set this value if the desired default is not `0`.
40+
/// - connectionPassword: The optional password to authenticate connections with. The default is `nil`.
41+
/// - connectionDefaultLogger: The optional prototype logger to use as the default logger instance when generating logs from connections.
42+
/// If one is not provided, one will be generated. See `RedisLogging.baseConnectionLogger`.
43+
/// - tcpClient: If you have chosen to configure a `NIO.ClientBootstrap` yourself, this will be used instead of the `.makeRedisTCPClient` factory instance.
44+
public init(
45+
connectionInitialDatabase: Int? = nil,
46+
connectionPassword: String? = nil,
47+
connectionDefaultLogger: Logger? = nil,
48+
tcpClient: ClientBootstrap? = nil
49+
) {
50+
self.init(
51+
connectionInitialDatabase: connectionInitialDatabase,
52+
connectionUsername: nil,
53+
connectionPassword: connectionPassword,
54+
connectionDefaultLogger: connectionDefaultLogger,
55+
tcpClient: tcpClient
56+
)
57+
}
58+
59+
/// Creates a new connection factory configuration with the provided options.
60+
/// - Parameters:
61+
/// - connectionInitialDatabase: The optional database index to initially connect to. The default is `nil`.
62+
/// Redis by default opens connections against index `0`, so only set this value if the desired default is not `0`.
63+
/// - connectionUsername: The optional username to authenticate connections with. The default is `nil`. Works only with Redis 6 and greater.
64+
/// - connectionPassword: The optional password to authenticate connections with. The default is `nil`.
65+
/// - connectionDefaultLogger: The optional prototype logger to use as the default logger instance when generating logs from connections.
66+
/// If one is not provided, one will be generated. See `RedisLogging.baseConnectionLogger`.
67+
/// - tcpClient: If you have chosen to configure a `NIO.ClientBootstrap` yourself, this will be used instead of the `.makeRedisTCPClient` factory instance.
68+
public init(
69+
connectionInitialDatabase: Int? = nil,
70+
connectionUsername: String? = nil,
71+
connectionPassword: String? = nil,
72+
connectionDefaultLogger: Logger? = nil,
73+
tcpClient: ClientBootstrap? = nil
74+
) {
75+
self.connectionInitialDatabase = connectionInitialDatabase
76+
self.connectionUsername = connectionUsername
77+
self.connectionPassword = connectionPassword
78+
self.connectionDefaultLogger = connectionDefaultLogger ?? RedisConnection.Configuration.defaultLogger
79+
self.tcpClient = tcpClient
80+
}
81+
}
82+
83+
/// A configuration object for connection pools.
84+
/// - Warning: This type has **reference** semantics due to `ConnectionFactoryConfiguration`.
85+
public struct Configuration {
86+
/// The set of Redis servers to which this pool is initially willing to connect.
87+
public let initialConnectionAddresses: [SocketAddress]
88+
/// The minimum number of connections to preserve in the pool.
89+
///
90+
/// If the pool is mostly idle and the Redis servers close these idle connections,
91+
/// the `RedisConnectionPool` will initiate new outbound connections proactively to avoid the number of available connections dropping below this number.
92+
public let minimumConnectionCount: Int
93+
/// The maximum number of connections to for this pool, either to be preserved or as a hard limit.
94+
public let maximumConnectionCount: RedisConnectionPoolSize
95+
/// The configuration object that controls the connection retry behavior.
96+
public let connectionRetryConfiguration: (backoff: (initialDelay: TimeAmount, factor: Float32), timeout: TimeAmount)
97+
/// Called when a connection in the pool is closed unexpectedly.
98+
public let onUnexpectedConnectionClose: ((RedisConnection) -> Void)?
99+
// these need to be var so they can be updated by the pool in some cases
100+
public internal(set) var factoryConfiguration: ConnectionFactoryConfiguration
101+
/// The logger prototype that will be used by the connection pool by default when generating logs.
102+
public internal(set) var poolDefaultLogger: Logger
103+
104+
/// Creates a new connection configuration with the provided options.
105+
/// - Parameters:
106+
/// - initialServerConnectionAddresses: The set of Redis servers to which this pool is initially willing to connect.
107+
/// This set can be updated over time directly on the connection pool.
108+
/// - maximumConnectionCount: The maximum number of connections to for this pool, either to be preserved or as a hard limit.
109+
/// - connectionFactoryConfiguration: The configuration to use while creating connections to fill the pool.
110+
/// - minimumConnectionCount: The minimum number of connections to preserve in the pool. If the pool is mostly idle
111+
/// and the Redis servers close these idle connections, the `RedisConnectionPool` will initiate new outbound
112+
/// connections proactively to avoid the number of available connections dropping below this number. Defaults to `1`.
113+
/// - connectionBackoffFactor: Used when connection attempts fail to control the exponential backoff. This is a multiplicative
114+
/// factor, each connection attempt will be delayed by this amount times the previous delay.
115+
/// - initialConnectionBackoffDelay: If a TCP connection attempt fails, this is the first backoff value on the reconnection attempt.
116+
/// Subsequent backoffs are computed by compounding this value by `connectionBackoffFactor`.
117+
/// - connectionRetryTimeout: The max time to wait for a connection to be available before failing a particular command or connection operation.
118+
/// The default is 60 seconds.
119+
/// - poolDefaultLogger: The `Logger` used by the connection pool itself.
120+
public init(
121+
initialServerConnectionAddresses: [SocketAddress],
122+
maximumConnectionCount: RedisConnectionPoolSize,
123+
connectionFactoryConfiguration: ConnectionFactoryConfiguration,
124+
minimumConnectionCount: Int = 1,
125+
connectionBackoffFactor: Float32 = 2,
126+
initialConnectionBackoffDelay: TimeAmount = .milliseconds(100),
127+
connectionRetryTimeout: TimeAmount? = .seconds(60),
128+
onUnexpectedConnectionClose: ((RedisConnection) -> Void)? = nil,
129+
poolDefaultLogger: Logger? = nil
130+
) {
131+
self.initialConnectionAddresses = initialServerConnectionAddresses
132+
self.maximumConnectionCount = maximumConnectionCount
133+
self.factoryConfiguration = connectionFactoryConfiguration
134+
self.minimumConnectionCount = minimumConnectionCount
135+
self.connectionRetryConfiguration = (
136+
(initialConnectionBackoffDelay, connectionBackoffFactor),
137+
connectionRetryTimeout ?? .milliseconds(10) // always default to a baseline 10ms
138+
)
139+
self.onUnexpectedConnectionClose = onUnexpectedConnectionClose
140+
self.poolDefaultLogger = poolDefaultLogger ?? .redisBaseConnectionPoolLogger
141+
}
142+
}
143+
}
144+
145+
/// `RedisConnectionPoolSize` controls how the maximum number of connections in a pool are interpreted.
146+
public enum RedisConnectionPoolSize {
147+
/// The pool will allow no more than this number of connections to be "active" (that is, connecting, in-use,
148+
/// or pooled) at any one time. This will force possible future users of new connections to wait until a currently
149+
/// active connection becomes available by being returned to the pool, but provides a hard upper limit on concurrency.
150+
case maximumActiveConnections(Int)
151+
152+
/// The pool will only store up to this number of connections that are not currently in-use. However, if the pool is
153+
/// asked for more connections at one time than this number, it will create new connections to serve those waiting for
154+
/// connections. These "extra" connections will not be preserved: while they will be used to satisfy those waiting for new
155+
/// connections if needed, they will not be preserved in the pool if load drops low enough. This does not provide a hard
156+
/// upper bound on concurrency, but does provide an upper bound on low-level load.
157+
case maximumPreservedConnections(Int)
158+
}

0 commit comments

Comments
 (0)