-
Notifications
You must be signed in to change notification settings - Fork 19
Description
I'm using Caffeine to cache a set of values from a server that refreshes every 60 seconds using refreshAfterWrite and an async reload.
The client that communicates with the server implicitly uses a security token that resides in a ThreadLocal<String> of some other singleton class. This means that when Caffeine uses reload to refresh its values, the security token is not set.
As such, I normally use Kotlin's ThreadContextElement to solve this problem, which configures the coroutine scope to transport the invoking thread's thread locals to any threads created by Kotlin under the current scope:
val valuesFromServer = runBlocking(Dispatchers.IO + CustomThreadContextElement()) {
val deferredValues = keys.map { async { getServerValue(it) } }
deferredValues.awaitAll()
}This is a problem in Caffeine, which is why I was happy to find your library Aedile. :)
However, there does not seem to be a way to have Aedile use the coroutine scope of the code block where the cache.get method is invoked (similar to async above), as I have to specify the scope for Aedile to use when building the cache at class level, where I have no way of accessing the scope where my ThreadContextElement is configured.
If I do not specify the scope, I can see from your code that you create a new scope which is used for the async coroutines. Since these do not use my coroutine scope, the context is lost.
class CachingClient {
private val cache = Caffeine.newBuilder()
.refreshAfterWrite(Duration.ofSeconds(60))
.asLoadingCache<String, String>(
// can only specify scope here
{ key ->
// my thread locals are `null` here since this code runs in a new thread
httpClient.getServerValue(key)
},
{ key, oldValue ->
try {
// my thread locals are `null` here since this code runs in a new thread
httpClient.getServerValue(key)
} catch (e: Throwable) {
oldValue
}
}
)
fun getServerValue(key: String): String {
// my thread locals are set on the current thread
val result = runBlocking(Dispatchers.IO + MyCustomThreadContextElement()) {
cache.get(key)
}
}
}Is there a way to have cache.get transport its coroutine scope to the internal async operations of Aedile?