Skip to content
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

Upgrade to RediStack 2.0 #203

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Update to RediStack Beta 1
  • Loading branch information
Mordil committed Nov 13, 2022
commit e4b31372f4684ac96cefe991a53bba2da91d26ab
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ let package = Package(
.library(name: "Redis", targets: ["Redis"])
],
dependencies: [
.package(url: "https://gitlab.com/mordil/RediStack.git", .revisionItem("9da5773e7a45f3fc38293ae1d66849a3f9093f56")),
.package(url: "https://gitlab.com/mordil/RediStack.git", .revisionItem("0465b34ef3f45c45d751100ef572c1afb4b1b50c")),
.package(url: "https://github.com/vapor/vapor.git", from: "4.50.0"),
],
targets: [
3 changes: 1 addition & 2 deletions Sources/Redis/Redis+Concurrency.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if compiler(>=5.5) && canImport(_Concurrency)
#if canImport(_Concurrency)
import NIOCore
import Vapor

@@ -149,5 +149,4 @@ extension Request.Redis {
}
}


#endif
156 changes: 91 additions & 65 deletions Sources/Redis/RedisConfiguration.swift
Original file line number Diff line number Diff line change
@@ -3,43 +3,68 @@
@_exported import struct NIO.TimeAmount
import enum NIO.SocketAddress

/// Configuration for connecting to a Redis instance
public struct RedisConfiguration {
/// Configuration for connection to one or more Redis instances with Vapor.
public typealias RedisConfiguration = RedisConnectionPool.Configuration

extension RedisConfiguration {
public typealias ValidationError = RedisConnection.Configuration.ValidationError

public var serverAddresses: [SocketAddress]
public var password: String?
public var database: Int?
public var pool: PoolOptions
public static var defaultConnectionCountBehavior: RedisConnectionPool.ConnectionCountBehavior {
return .strict(maximumConnectionCount: 2, minimumConnectionCount: 0)
}
public static var defaultRetryStrategy: RedisConnectionPool.PoolConnectionRetryStrategy { .exponentialBackoff() }
}

public struct PoolOptions {
public var maximumConnectionCount: RedisConnectionPoolSize
public var minimumConnectionCount: Int
public var connectionBackoffFactor: Float32
public var initialConnectionBackoffDelay: TimeAmount
public var connectionRetryTimeout: TimeAmount?
// MARK: Convenience Initializers

public init(
maximumConnectionCount: RedisConnectionPoolSize = .maximumActiveConnections(2),
minimumConnectionCount: Int = 0,
connectionBackoffFactor: Float32 = 2,
initialConnectionBackoffDelay: TimeAmount = .milliseconds(100),
connectionRetryTimeout: TimeAmount? = nil
) {
self.maximumConnectionCount = maximumConnectionCount
self.minimumConnectionCount = minimumConnectionCount
self.connectionBackoffFactor = connectionBackoffFactor
self.initialConnectionBackoffDelay = initialConnectionBackoffDelay
self.connectionRetryTimeout = connectionRetryTimeout
}
extension RedisConfiguration {
public init(
hostname: String,
port: Int = RedisConnection.Configuration.defaultPort,
password: String? = nil,
database: Int? = nil,
connectionCountBehavior: RedisConnectionPool.ConnectionCountBehavior = Self.defaultConnectionCountBehavior,
connectionRetryStrategy: RedisConnectionPool.PoolConnectionRetryStrategy = Self.defaultRetryStrategy,
poolDefaultLogger: Logger? = nil,
connectionDefaultLogger: Logger? = nil
) throws {
self.init(
initialServerConnectionAddresses: [try .makeAddressResolvingHost(hostname, port: port)],
connectionCountBehavior: connectionCountBehavior,
connectionConfiguration: .init(
initialDatabase: database,
password: password,
defaultLogger: connectionDefaultLogger
),
retryStrategy: connectionRetryStrategy,
poolDefaultLogger: poolDefaultLogger
)
}

public init(url string: String, pool: PoolOptions = .init()) throws {
public init(
url string: String,
connectionCountBehavior: RedisConnectionPool.ConnectionCountBehavior = Self.defaultConnectionCountBehavior,
connectionRetryStrategy: RedisConnectionPool.PoolConnectionRetryStrategy = Self.defaultRetryStrategy,
poolDefaultLogger: Logger? = nil,
connectionDefaultLogger: Logger? = nil
) throws {
guard let url = URL(string: string) else { throw ValidationError.invalidURLString }
try self.init(url: url, pool: pool)
try self.init(
url: url,
connectionCountBehavior: connectionCountBehavior,
connectionRetryStrategy: connectionRetryStrategy,
poolDefaultLogger: poolDefaultLogger,
connectionDefaultLogger: connectionDefaultLogger
)
}

public init(url: URL, pool: PoolOptions = .init()) throws {
public init(
url: URL,
connectionCountBehavior: RedisConnectionPool.ConnectionCountBehavior = Self.defaultConnectionCountBehavior,
connectionRetryStrategy: RedisConnectionPool.PoolConnectionRetryStrategy = Self.defaultRetryStrategy,
poolDefaultLogger: Logger? = nil,
connectionDefaultLogger: Logger? = nil
) throws {
guard
let scheme = url.scheme,
!scheme.isEmpty
@@ -52,56 +77,57 @@ public struct RedisConfiguration {
port: url.port ?? RedisConnection.Configuration.defaultPort,
password: url.password,
database: Int(url.lastPathComponent),
pool: pool
connectionCountBehavior: connectionCountBehavior,
connectionRetryStrategy: connectionRetryStrategy,
poolDefaultLogger: poolDefaultLogger,
connectionDefaultLogger: connectionDefaultLogger
)
}

public init(
hostname: String,
port: Int = RedisConnection.Configuration.defaultPort,
serverAddresses: [SocketAddress],
password: String? = nil,
database: Int? = nil,
pool: PoolOptions = .init()
) throws {
if database != nil && database! < 0 { throw ValidationError.outOfBoundsDatabaseID }

try self.init(
serverAddresses: [.makeAddressResolvingHost(hostname, port: port)],
password: password,
database: database,
pool: pool
connectionCountBehavior: RedisConnectionPool.ConnectionCountBehavior = Self.defaultConnectionCountBehavior,
connectionRetryStrategy: RedisConnectionPool.PoolConnectionRetryStrategy = Self.defaultRetryStrategy,
poolDefaultLogger: Logger? = nil,
connectionDefaultLogger: Logger? = nil
) {
self.init(
initialServerConnectionAddresses: serverAddresses,
connectionCountBehavior: connectionCountBehavior,
connectionConfiguration: .init(
initialDatabase: database,
password: password,
defaultLogger: connectionDefaultLogger
),
retryStrategy: connectionRetryStrategy,
poolDefaultLogger: poolDefaultLogger
)
}
}

public init(
serverAddresses: [SocketAddress],
password: String? = nil,
database: Int? = nil,
pool: PoolOptions = .init()
) throws {
self.serverAddresses = serverAddresses
self.password = password
self.database = database
self.pool = pool
// MARK: Internal Configuration Creation

extension RedisConnectionPool.PoolConnectionConfiguration {
internal func logging(to newLogger: Logger) -> Self {
return .init(
initialDatabase: self.initialDatabase,
password: self.password,
defaultLogger: newLogger,
tcpClient: self.tcpClient
)
}
}

extension RedisConnectionPool.Configuration {
internal init(_ config: RedisConfiguration, defaultLogger: Logger) {
self.init(
initialServerConnectionAddresses: config.serverAddresses,
maximumConnectionCount: config.pool.maximumConnectionCount,
connectionFactoryConfiguration: .init(
connectionInitialDatabase: config.database,
connectionPassword: config.password,
connectionDefaultLogger: defaultLogger,
tcpClient: nil
),
minimumConnectionCount: config.pool.minimumConnectionCount,
connectionBackoffFactor: config.pool.connectionBackoffFactor,
initialConnectionBackoffDelay: config.pool.initialConnectionBackoffDelay,
connectionRetryTimeout: config.pool.connectionRetryTimeout,
poolDefaultLogger: defaultLogger
internal func logging(to newLogger: Logger) -> Self {
return .init(
initialServerConnectionAddresses: self.initialConnectionAddresses,
connectionCountBehavior: self.connectionCountBehavior,
connectionConfiguration: self.connectionConfiguration.logging(to: newLogger),
retryStrategy: self.retryStrategy,
poolDefaultLogger: newLogger
)
}
}
5 changes: 3 additions & 2 deletions Sources/Redis/RedisStorage.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import struct NIOConcurrencyHelpers.NIOLock
import Vapor

extension Application {
@@ -17,7 +18,7 @@ extension Application {
}

final class RedisStorage {
private var lock: Lock
private var lock: NIOLock
private var configurations: [RedisID: RedisConfiguration]
fileprivate var pools: [PoolKey: RedisConnectionPool] {
willSet {
@@ -75,7 +76,7 @@ extension RedisStorage {
let newKey: PoolKey = PoolKey(eventLoopKey: eventLoop.key, redisID: redisID)

let newPool = RedisConnectionPool(
configuration: .init(configuration, defaultLogger: application.logger),
configuration: configuration.logging(to: application.logger),
boundEventLoop: eventLoop)

newPools[newKey] = newPool
4 changes: 2 additions & 2 deletions Tests/RedisTests/RedisTests.swift
Original file line number Diff line number Diff line change
@@ -66,8 +66,8 @@ extension RedisTests {

let redisConfiguration = try RedisConfiguration(url: urlStr!)

XCTAssertEqual(redisConfiguration.password, "password")
XCTAssertEqual(redisConfiguration.database, 0)
XCTAssertEqual(redisConfiguration.connectionConfiguration.password, "password")
XCTAssertEqual(redisConfiguration.connectionConfiguration.initialDatabase, 0)
}
}