Cache
You’ll often want to cache the results of expensive or long running operations to save CPU time and respond to future requests faster. Alchemy provides a Cache
type for easily interacting with common caching backends.
Configuration
Cache conforms to Service
and can be configured like other Alchemy services with the config
function. Out of the box, providers are provided for Redis and SQL based caches as well as an in memory mock cache.
Cache.config(default: .redis())
If you’re using the Cache.sql()
cache configuration, you’ll need to add the Cache.AddCacheMigration
migration to your database’s migrations.
Database.default.migrations = [
Cache.AddCacheMigration(),
...
]
Interacting with the Cache
Storing Items in the Cache
You can store values to the cache using the set()
function.
cache.set("num_unique_users", 62, for: .seconds(60))
The third parameter is optional and if not passed the value will be stored indefinitely.
Storing Custom Types
You can store any type that conforms to CacheAllowed
in a cache. Out of the box, Bool
, String
, Int
, and Double
are supported, but you can easily store your own types as well.
extension URL: CacheAllowed {
public var stringValue: String {
return absoluteString
}
public init?(_ string: String) {
self.init(string: string)
}
}
Retreiving Cache Items
Once set, a value can be retrived using get()
.
cache.get("num_unique_users")
Checking for item existence
You can check if a cache contains a specific item using has()
.
cache.has("\(user.id)_last_login")
Incrementing and Decrementing items
When working with numerical cache values, you can use increment()
and decrement()
.
cache.increment("key")
cache.increment("key", by: 4)
cache.decrement("key")
cache.decrement("key", by: 4)
Removing Items from the Cache
You can use delete()
to clear an item from the cache.
cache.delete(key)
Using remove()
, you can clear and return a cache item.
let value = cache.remove(key)
If you’d like to clear all data from a cache, you may use wipe.
cache.wipe()
Adding a Custom Cache Provider
If you’d like to add a custom provider for cache, you can implement the CacheProvider
protocol.
struct MemcachedCache: CacheProvider {
func get<L: LosslessStringConvertible>(_ key: String) -> EventLoopFuture<C?> {
...
}
func set<L: LosslessStringConvertible>(_ key: String, value: C, for time: TimeAmount?) -> EventLoopFuture<Void> {
...
}
func has(_ key: String) -> EventLoopFuture<Bool> {
...
}
func remove<L: LosslessStringConvertible>(_ key: String) -> EventLoopFuture<C?> {
...
}
func delete(_ key: String) -> EventLoopFuture<Void> {
...
}
func increment(_ key: String, by amount: Int) -> EventLoopFuture<Int> {
...
}
func decrement(_ key: String, by amount: Int) -> EventLoopFuture<Int> {
...
}
func wipe() -> EventLoopFuture<Void> {
...
}
}
Then, add a static configuration function for using your new cache backend.
extension Cache {
static func memcached() -> Cache {
Cache(MemcachedCache())
}
}
Cache.config(default: .memcached())