diff --git a/aedile-core/src/main/kotlin/com/sksamuel/aedile/core/LoadingCache.kt b/aedile-core/src/main/kotlin/com/sksamuel/aedile/core/LoadingCache.kt index 2b7f76f..7432f87 100644 --- a/aedile-core/src/main/kotlin/com/sksamuel/aedile/core/LoadingCache.kt +++ b/aedile-core/src/main/kotlin/com/sksamuel/aedile/core/LoadingCache.kt @@ -175,6 +175,26 @@ class LoadingCache( cache.synchronous().invalidateAll() } + /** + * Loads a new value for the key, asynchronously. While the new value is loading the + * previous value (if any) will continue to be returned by get(key) unless it is evicted. + * + * See full docs at [com.github.benmanes.caffeine.cache.LoadingCache.refresh]. + */ + fun refresh(key: K) { + cache.synchronous().refresh(key) + } + + /** + * Loads a new value for each key, asynchronously. While the new value is loading the + * previous value (if any) will continue to be returned by get(key) unless it is evicted. + * + * See full docs at [com.github.benmanes.caffeine.cache.LoadingCache.refreshAll]. + */ + fun refreshAll(keys: Collection) { + cache.synchronous().refreshAll(keys) + } + private suspend fun scope(): CoroutineScope { return if (useCallingContext) CoroutineScope(coroutineContext) else defaultScope } diff --git a/aedile-core/src/test/kotlin/com/sksamuel/aedile/core/AsLoadingCacheTest.kt b/aedile-core/src/test/kotlin/com/sksamuel/aedile/core/AsLoadingCacheTest.kt index b13d32f..08cbf0e 100644 --- a/aedile-core/src/test/kotlin/com/sksamuel/aedile/core/AsLoadingCacheTest.kt +++ b/aedile-core/src/test/kotlin/com/sksamuel/aedile/core/AsLoadingCacheTest.kt @@ -2,6 +2,7 @@ package com.sksamuel.aedile.core import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Expiry +import io.kotest.assertions.nondeterministic.eventually import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec @@ -13,6 +14,7 @@ import kotlinx.coroutines.yield import org.checkerframework.checker.index.qual.NonNegative import java.util.concurrent.atomic.AtomicInteger import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds class AsLoadingCacheTest : FunSpec() { init { @@ -319,6 +321,34 @@ class AsLoadingCacheTest : FunSpec() { cache.contains("bubble") shouldBe false } + test("support refresh") { + var counter = 0 + val cache = Caffeine.newBuilder().asLoadingCache { + counter++ + counter + } + cache.get("foo") shouldBe 1 + cache.refresh("foo") + eventually(5.seconds) { + cache.get("foo") shouldBe 2 + } + } + + test("support refresh all") { + var counter = 0 + val cache = Caffeine.newBuilder().asLoadingCache { + counter++ + counter + } + cache.get("foo") shouldBe 1 + cache.get("bar") shouldBe 2 + cache.refreshAll(setOf("foo", "bar")) + eventually(5.seconds) { + cache.get("foo") shouldBe 3 + cache.get("bar") shouldBe 4 + } + } + test("check invariants on expire after") { val loggerExpiry = object : Expiry { override fun expireAfterRead(