@@ -16,6 +16,13 @@ public struct RedisConfiguration: Sendable {
16
16
public var tlsConfiguration : TLSConfiguration ?
17
17
public var tlsHostname : String ?
18
18
19
+ internal var deferredHostname : String ?
20
+ internal var deferredPort : Int ?
21
+
22
+ public var hasUnresolvedHostname : Bool {
23
+ return deferredHostname != nil
24
+ }
25
+
19
26
public struct PoolOptions : Sendable {
20
27
public var maximumConnectionCount : RedisConnectionPoolSize
21
28
public var minimumConnectionCount : Int
@@ -83,14 +90,22 @@ public struct RedisConfiguration: Sendable {
83
90
) throws {
84
91
if database != nil && database! < 0 { throw ValidationError . outOfBoundsDatabaseID }
85
92
86
- try self . init (
87
- serverAddresses: [ . makeAddressResolvingHost( hostname, port: port) ] ,
88
- password: password,
89
- tlsConfiguration: tlsConfiguration,
90
- tlsHostname: hostname,
91
- database: database,
92
- pool: pool
93
- )
93
+ do {
94
+ let resolvedAdress = try SocketAddress . makeAddressResolvingHost ( hostname, port: port)
95
+ self . serverAddresses = [ resolvedAdress]
96
+ self . deferredHostname = nil
97
+ self . deferredPort = nil
98
+ } catch {
99
+ self . serverAddresses = [ ]
100
+ self . deferredHostname = hostname
101
+ self . deferredPort = port
102
+ }
103
+
104
+ self . password = password
105
+ self . tlsConfiguration = tlsConfiguration
106
+ self . tlsHostname = hostname
107
+ self . database = database
108
+ self . pool = pool
94
109
}
95
110
96
111
public init (
@@ -102,18 +117,48 @@ public struct RedisConfiguration: Sendable {
102
117
pool: PoolOptions = . init( )
103
118
) throws {
104
119
self . serverAddresses = serverAddresses
120
+ self . deferredHostname = nil
121
+ self . deferredPort = nil
105
122
self . password = password
106
123
self . tlsConfiguration = tlsConfiguration
107
124
self . tlsHostname = tlsHostname
108
125
self . database = database
109
126
self . pool = pool
110
127
}
128
+
129
+ /// Attempts to resolve any pending hostname resolution
130
+ /// - Returns: new configuration with resolved addresses, or throws if resolution fails
131
+ public func resolveServerAddresses( ) throws -> RedisConfiguration {
132
+ guard let hostname = deferredHostname, let port = deferredPort else {
133
+ return self
134
+ }
135
+
136
+ var resolved = self
137
+ let resolvedAddress = try SocketAddress . makeAddressResolvingHost ( hostname, port: port)
138
+ resolved. serverAddresses = [ resolvedAddress]
139
+ resolved. deferredHostname = nil
140
+ resolved. deferredPort = nil
141
+ return resolved
142
+ }
111
143
}
112
144
113
145
extension RedisConnectionPool . Configuration {
114
146
internal init ( _ config: RedisConfiguration , defaultLogger: Logger , customClient: ClientBootstrap ? ) {
147
+ // Handle deferred hostname resolution at pool creation time
148
+ var addresses = config. serverAddresses
149
+
150
+ if let hostname = config. deferredHostname, let port = config. deferredPort {
151
+ do {
152
+ let resolvedAddress = try SocketAddress . makeAddressResolvingHost ( hostname, port: port)
153
+ addresses = [ resolvedAddress]
154
+ } catch {
155
+ defaultLogger. notice ( " Hostname ' \( hostname) ' could not be resolved at pool creation time: \( error) . Redis connections will fail until hostname becomes resolvable. " )
156
+ // Placeholder address so Redis operations fail gracefully
157
+ addresses = [ try ! SocketAddress . makeAddressResolvingHost ( " 0.0.0.0 " , port: 1 ) ]
158
+ }
159
+ }
115
160
self . init (
116
- initialServerConnectionAddresses: config . serverAddresses ,
161
+ initialServerConnectionAddresses: addresses ,
117
162
maximumConnectionCount: config. pool. maximumConnectionCount,
118
163
connectionFactoryConfiguration: . init(
119
164
connectionInitialDatabase: config. database,
0 commit comments