SwiftでValkeyを使う方法を簡単に紹介
Valkey
ValkeyとはRedis v7.2.4からのフォークです。
Redisはv8からのライセンスがAGPLv3に変わり、ValkeyのBSDとは異なり、ライセンス周りがかなり自由です。
Valkey for Swift
Swiftで書かれたクライアントのSDKが公式で公開されています。こちらの使い方を簡単に紹介します。
Valkey(Redis)の基礎
RDBS(SQL)と異なり、Key/Value形式で管理されています。
保存/取得のコマンドがRDBS(SQL)より、用途別で細かく用意されています。
すべては紹介しきれないため、よく使いそうなものだけ紹介します。
Valkey-Swift
Valkey-Swiftは最初にrun()を別Taskで走らせておく必要があります。
これをしないとValkeyにコマンドを送っても何も返ってきません。
import Valkey
let client = ValkeyClient(.hostname("localhost", port: 6379), logger: logger)
Task {
await client.run()
}
let data = try await client.get("Key")
SET: 値の保存
TestKey
というキーで、TestValue
という値を保存する
import Valkey
let client: ValkeyClient
try await client.set(
"TestKey", // キー
value: "TestValue", // 値
expiration: .seconds(60) // 有効期限(保存期間)
)
GET: 値の取得
TestKey
というキーで値を取得する
import Valkey
let client: ValkeyClient
guard let buffer = try await client.get("TestKey") else {
print("Not Found")
return
}
let value = String(buffer: buffer)
print(value)
DEL: キー/値の削
import Valkey
let client: ValkeyClient
try await client.del(keys: ["Key1", "Key2"])
SET: Encodableの保存方法
import Valkey
let client: ValkeyClient
struct User: Codable {
var id: UUID
var name: String
var age: Int
}
let user = User(id: UUID(), name: "Bob", age: 20)
let data = try JSONEncoder().encode(user)
try await client.set(
ValkeyKey("users:\(user.id)"),
value: data
)
GET: Decodableの取得方法
let userId: UUID
guard let buffer = try await client.get(
"users:\(userId.uuidString)"
) else {
print("Not Found")
return
}
let user = try JSONDecoder().decode(User.self, from: buffer)
print(user)
MSET: Array<Encodable>の保存方法
MSETは複数のKey/Valueの組み合わせを1回で保存でコマンドです。
import Valkey
import NIOCore
let client: ValkeyClient
struct User: Codable {
var id: UUID
var name: String
var age: Int
}
func save(users: [User]) async throws {
let encoder = JSONEncoder()
let datas = try users.map { ($0.id, try encoder.encode($0)) }
try await client.mset(
data: datas.map { .init(key: ValkeyKey("users:\($0.0.uuidString)"), value: $0.1)}
)
}
MGET: Array<Decodable>の取得方法
MGETは複数のキーを渡して、1回で複数の値を取得できるコマンドです。
import Valkey
import NIOCore
let client: ValkeyClient
struct User: Codable {
var id: UUID
var name: String
var age: Int
}
func fetchUsers(ids: [UUID]) async throws -> [User] {
let usersData: RESPToken.Array = try await client.mget(
keys: ids.map { ValkeyKey("users:\($0.uuidString)") }
)
let decoder = JSONDecoder()
let users: [User] = try usersData.map {
try decoder.decode(User.self, from: $0.decode(as: ByteBuffer.self))
}
return users
}
connection
withConnectionを使って、コマンドをまとめて実行することが可能です。
try await client.withConnection { connection in
connection.set("Key1", value: "Value1")
connection.set("Key2", value: "Value2")
}
Vapor対応
Vaporではキャッシュのツールとしてvapor/redisが用意されていますが、Swift 6に対応する予定のVapor v5
には対応しなさそうな雰囲気を勝手に感じています。
https://github.com/swift-server/RediStack/issues/129#issuecomment-3144264639
It might be worth checking out the new Valkey library that's written from scratch with Swift concurrency in mind - https://github.com/valkey-io/valkey-swift
なのでValkeyVaporを作成しました。vapor/redisのようにVapor上で使うことができます。
Discussion