Skip to content

[Question] Does Aedile support ThreadContextElement? #44

@olaisolheim

Description

@olaisolheim

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions