I am building a Swift-on-server project that will use a cache. There are libraries for caches based on Redis and other data stores, but as far as I can tell, none of them are atomic.
It seems like Actors are just the ticket here, but I’m not getting over the finish line.
Getting an item from cache should be a process something like:
- If the key is defined in cache, return it.
- If the key is not defined, but another process is creating the data, wait until that is finished, and return the result.
- If the key is not defined, and no other process is defining it, calculate the value and put it into cache.
Actors seem like a good solution to this problem, almost. Imagine an actor something like (this is pretty much swifty pseudocode, but it shows a rough outline of the process):
actor CacheItem {
private let key: String
private let storage: <Storage Class of choice>
private var value: String?
init (key: String, backingStorage: <Storage Class of choice>) {
// set the stuff
}
func get() async -> String {
if let value {
return value
}
return await fillIfNotExists()
}
// this mutates the actor, so should force anything trying to read `value` to wait
func fillIfNotExists() async -> String
return storage.get(key).flatMap { response in
if let value = response {
return response
}
// Create the value (will potentially include asynchronous calls as well)
value = // ...
await storage.set(key, to: value)
return value
}
}
}
However, the documentation says (emphasis mine),
… code that doesn’t include await and that’s inside an actor can make the updates without a risk of other places in your program observing the temporarily invalid state.”
There is more discussion on that page about the way threads are used for actors, and it sounds like it depends on control not being yielded on that thread during the mutating function.
Reading and writing from cache will definitely be asynchronous. Is that going to break the atomicity of my CacheItem
s? Is there a workaround, maybe with added state in the CacheItem
, to get the desired behavior?
Edit to add thank you to @duck in the comments for adding reentrancy
to my vocabulary. Reading more has led me to believe at this time that Actor
is simply not the tool for this job. I’m now thinking about an Actor
that (waves hands) is a broker for mutex keys.
6