From 9c90f1dc338dae2b87baaf32e299246355091a40 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Fri, 12 Sep 2025 17:13:36 +0100 Subject: [PATCH] Replace HummingbirdRedis with HummingbirdValkey --- Hummingbird.docc/Articles/PersistentData.md | 14 ++-- Hummingbird.docc/HummingbirdAuth/Sessions.md | 2 +- .../HummingbirdRedis/HummingbirdRedis.md | 71 ------------------- .../RedisConnectionPoolService.md | 24 ------- .../HummingbirdValkey/HummingbirdValkey.md | 45 ++++++++++++ Hummingbird.docc/JobsRedis/JobsRedis.md | 34 +-------- Hummingbird.docc/index.md | 2 +- Package.swift | 4 +- 8 files changed, 57 insertions(+), 139 deletions(-) delete mode 100644 Hummingbird.docc/HummingbirdRedis/HummingbirdRedis.md delete mode 100644 Hummingbird.docc/HummingbirdRedis/RedisConnectionPoolService.md create mode 100644 Hummingbird.docc/HummingbirdValkey/HummingbirdValkey.md diff --git a/Hummingbird.docc/Articles/PersistentData.md b/Hummingbird.docc/Articles/PersistentData.md index b83fa90a96..57d2e05fa2 100644 --- a/Hummingbird.docc/Articles/PersistentData.md +++ b/Hummingbird.docc/Articles/PersistentData.md @@ -64,15 +64,15 @@ let persist = MemoryPersistDriver() ``` If you use the memory based driver the key/value pairs you store will be lost if your server goes down, also you will not be able to share values between server processes. -### Redis +### Valkey/Redis -You can use Redis to store the `persists` key/value pairs with ``HummingbirdRedis/RedisPersistDriver`` from the `HummingbirdRedis` library. You would setup `persist` to use Redis as follows. +You can use Valkey/Redis to store the `persists` key/value pairs with ``HummingbirdValkey/ValkeyPersistDriver`` from the `HummingbirdValkey` library. You would setup `persist` to use Valkey as follows. ```swift -let redis = RedisConnectionPoolService( - .init(hostname: redisHostname, port: 6379), - logger: Logger(label: "Redis") +let valkeyClient = ValkeyClient( + .hostname(valkeyHostname, port: 6379), + logger: Logger(label: "Valkey") ) -let persist = RedisPersistDriver(redisConnectionPoolService: redis) +let persist = ValkeyPersistDriver(client: valkeyClient) ``` ### Fluent @@ -93,5 +93,5 @@ if shouldMigrate { - ``PersistDriver`` - ``MemoryPersistDriver`` - ``HummingbirdFluent/FluentPersistDriver`` -- ``HummingbirdRedis/RedisPersistDriver`` +- ``HummingbirdValkey/ValkeyPersistDriver`` - ``HummingbirdPostgres/PostgresPersistDriver`` diff --git a/Hummingbird.docc/HummingbirdAuth/Sessions.md b/Hummingbird.docc/HummingbirdAuth/Sessions.md index 6d140c235f..09edddf330 100644 --- a/Hummingbird.docc/HummingbirdAuth/Sessions.md +++ b/Hummingbird.docc/HummingbirdAuth/Sessions.md @@ -12,7 +12,7 @@ Sessions allow you to persist state eg user authentication status between multip The ``HummingbirdAuth/SessionMiddleware`` is used to extract and save session state from the RequestContext. To use it, your `RequestContext` must conform to ``HummingbirdAuth/SessionRequestContext``. Adding the `SessionMiddleware` to your middleware stack will mean any middleware or routes after will have read/write access to session state via the member ``HummingbirdAuth/SessionRequestContext/sessions``. -The `SessionMiddleware` needs a persist key value store to save its state. You can find out more about the persist framework here . In the example below we are using an in memory key value store, but ``HummingbirdFluent/FluentPersistDriver`` and ``HummingbirdRedis/RedisPersistDriver`` provide solutions that stores the session data in a database or redis database respectively. +The `SessionMiddleware` needs a persist key value store to save its state. You can find out more about the persist framework here . In the example below we are using an in memory key value store, but ``HummingbirdFluent/FluentPersistDriver`` and ``HummingbirdValkey/ValkeyPersistDriver`` provide solutions that stores the session data in a database or valkey/redis database respectively. ```swift router.add( diff --git a/Hummingbird.docc/HummingbirdRedis/HummingbirdRedis.md b/Hummingbird.docc/HummingbirdRedis/HummingbirdRedis.md deleted file mode 100644 index 7b16deb725..0000000000 --- a/Hummingbird.docc/HummingbirdRedis/HummingbirdRedis.md +++ /dev/null @@ -1,71 +0,0 @@ -# ``HummingbirdRedis`` - -@Metadata { - @PageImage(purpose: icon, source: "logo") -} - -Add Redis support to Hummingbird server with RediStack. - -## Overview - -Adds Redis support to Hummingbird via [RediStack](https://github.com/swift-server/RediStack) and manage the lifecycle of your Redis connection pool. Also provides a Redis based driver for the persist framework. - -```swift -let redis = try RedisConnectionPoolService( - .init(hostname: Self.redisHostname, port: 6379), - logger: Logger(label: "Redis") -) -// add router with one route to return Redis info -let router = Router() -router.get("redis") { _, _ in - try await redis.send(command: "INFO").map(\.description).get() -} -var app = Application(router: router) -// add Redis connection pool as a service to manage its lifecycle -app.addServices(redis) -try await app.runService() -``` - -## Storage - -HummingbirdRedis provides a driver for the persist framework to store key, value pairs between requests. - -```swift -let redis = try RedisConnectionPoolService( - .init(hostname: Self.redisHostname, port: 6379), - logger: Logger(label: "Redis") -) -let persist = RedisPersistDriver(redisConnectionPoolService: redis) -let router = Router() -// return value from redis database -router.get("{id}") { request, context -> String? in - let id = try context.parameters.require("id") - try await persist.get(key: id, as: String.self) -} -// set value in redis database -router.put("{id}") { request, context -> String? in - let id = try context.parameters.require("id") - let value = try request.uri.queryParameters.require("value") - try await persist.set(key: id, value: value) -} -var app = Application(router: router) -// add Redis connection pool and persist driver as services to manage their lifecycle -app.addServices(redis, persist) -try await app.runService() -``` - - -## Topics - -### Connection Pool - -- ``RedisConnectionPoolService`` -- ``RedisConfiguration`` - -### Storage - -- ``RedisPersistDriver`` - -## See Also - -- ``JobsRedis`` \ No newline at end of file diff --git a/Hummingbird.docc/HummingbirdRedis/RedisConnectionPoolService.md b/Hummingbird.docc/HummingbirdRedis/RedisConnectionPoolService.md deleted file mode 100644 index 56111028ed..0000000000 --- a/Hummingbird.docc/HummingbirdRedis/RedisConnectionPoolService.md +++ /dev/null @@ -1,24 +0,0 @@ -# ``HummingbirdRedis/RedisConnectionPoolService`` - -## Overview - -`RedisConnectionPoolService` is a wrapper for a redis connection pool which also conforms to `Service` from [Swift Service Lifecycle](https://github.com/swift-server/swift-service-lifecycle). - -```swift -// Create a Redis Connection Pool -let redis = try RedisConnectionPoolService( - .init( - hostname: Self.redisHostname, - port: 6379, - pool: .init(maximumConnectionCount: 32) - ), - logger: Logger(label: "Redis") -) -// Call Redis function. Currently there are no async/await versions -// of the functions so have to call `get` to await for EventLoopFuture result -try await redis.set("Test", to: "hello").get() -``` - -## Service Lifecycle - -Given `RedisConnectionPoolService` conforms to `Service` you can have its lifecycle managed by either adding it to the Hummingbird `ServiceGroup` using ``/Hummingbird/Application/addServices(_:)`` from ``/Hummingbird/Application`` or adding it to an independently managed `ServiceGroup`. diff --git a/Hummingbird.docc/HummingbirdValkey/HummingbirdValkey.md b/Hummingbird.docc/HummingbirdValkey/HummingbirdValkey.md new file mode 100644 index 0000000000..e4e0b67b69 --- /dev/null +++ b/Hummingbird.docc/HummingbirdValkey/HummingbirdValkey.md @@ -0,0 +1,45 @@ +# ``HummingbirdValkey`` + +@Metadata { + @PageImage(purpose: icon, source: "logo") +} + +Add Valkey/Redis support to Hummingbird server with valkey-swift. + +## Overview + +HummingbirdValkey provides a driver for the Hummingbird persist framework to store key, value pairs between requests. + +```swift +let valkeyClient = ValkeyClient( + .hostname(Self.valkeyHostname, port: 6379), + logger: Logger(label: "Valkey") +) +let persist = ValkeyPersistDriver(client: valkeyClient) +let router = Router() +// return value from valkey database +router.get("{id}") { request, context -> String? in + let id = try context.parameters.require("id") + try await persist.get(key: id, as: String.self) +} +// set value in valkey database +router.put("{id}") { request, context -> String? in + let id = try context.parameters.require("id") + let value = try request.uri.queryParameters.require("value") + try await persist.set(key: id, value: value) +} +var app = Application(router: router) +// add Valkey client as service to manage its lifecycle +app.addServices(valkeyClient) +try await app.runService() +``` + +## Topics + +### Storage + +- ``ValkeyPersistDriver`` + +## See Also + +- ``JobsRedis`` \ No newline at end of file diff --git a/Hummingbird.docc/JobsRedis/JobsRedis.md b/Hummingbird.docc/JobsRedis/JobsRedis.md index fc0a70df0b..de58009572 100644 --- a/Hummingbird.docc/JobsRedis/JobsRedis.md +++ b/Hummingbird.docc/JobsRedis/JobsRedis.md @@ -12,39 +12,7 @@ Hummingbird Jobs Queue driver using [RediStack](https://github.com/swift-server/ ### Setup -Currently `RediStack` is not setup to use `ServiceLifecycle`. So to ensure clean shutdown of `RediStack` you either need to use the ``HummingbirdRedis/RedisConnectionPoolService`` that is part of ``HummingbirdRedis`` or write your own `Service` type that will manage the shutdown of a `RedisConnectionPool`. - -#### Using HummingbirdRedis - -If you choose to use `HummingbirdRedis` you can setup a JobQueue using `RediStack` as follows - -```swift -let redisService = try RedisConnectionPoolService( - .init(hostname: redisHost, port: 6379), - logger: logger -) -let jobQueue = JobQueue( - .redis( - redisService.pool, - configuration: .init( - queueKey: "MyJobQueue", - pollTime: .milliseconds(50) - ) - ), - logger: logger -) -let serviceGroup = ServiceGroup( - configuration: .init( - services: [redisService, jobQueue], - gracefulShutdownSignals: [.sigterm, .sigint], - logger: logger - ) -) -try await serviceGroup.run() -``` -The Redis job queue configuration includes two values. -- `queueKey`: Prefix to all the Redis keys used to store queues. -- `pollTime`: This is the amount of time between the last time the queue was empty and the next time the driver starts looking for pending jobs. +Currently `RediStack` is not setup to use `ServiceLifecycle`. So to ensure clean shutdown of `RediStack` you need to create your own `Service` type that will manage the shutdown of a `RedisConnectionPool`. #### Write RedisConnectionPool Service diff --git a/Hummingbird.docc/index.md b/Hummingbird.docc/index.md index 17914c697f..57edcbbbe9 100644 --- a/Hummingbird.docc/index.md +++ b/Hummingbird.docc/index.md @@ -86,7 +86,7 @@ Below is a list of guides and tutorials to help you get started with building yo - ``/HummingbirdFluent`` - ``/HummingbirdLambda`` - ``/HummingbirdPostgres`` -- ``/HummingbirdRedis`` +- ``/HummingbirdValkey`` - ``/HummingbirdWebSocket`` - ``/Jobs`` - ``/Mustache`` diff --git a/Package.swift b/Package.swift index 2b4b2eb353..2bb8983481 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/hummingbird-project/swift-mustache.git", from: "2.0.0"), .package(url: "https://github.com/hummingbird-project/hummingbird-postgres.git", from: "1.0.0-rc"), .package(url: "https://github.com/hummingbird-project/postgres-migrations.git", from: "1.0.0-rc"), - .package(url: "https://github.com/hummingbird-project/hummingbird-redis.git", from: "2.0.0"), + .package(url: "https://github.com/hummingbird-project/hummingbird-valkey.git", from: "0.1.1"), .package(url: "https://github.com/hummingbird-project/hummingbird-websocket.git", from: "2.2.0"), .package(url: "https://github.com/hummingbird-project/swift-websocket.git", from: "1.2.0"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), @@ -54,7 +54,7 @@ let package = Package( .product(name: "Mustache", package: "swift-mustache"), .product(name: "HummingbirdPostgres", package: "hummingbird-postgres"), .product(name: "PostgresMigrations", package: "postgres-migrations"), - .product(name: "HummingbirdRedis", package: "hummingbird-redis"), + .product(name: "HummingbirdValkey", package: "hummingbird-valkey"), .product(name: "HummingbirdWebSocket", package: "hummingbird-websocket"), .product(name: "WSClient", package: "swift-websocket"), .product(name: "WSCompression", package: "swift-websocket"),