Fedor Bobin
02/17/2018, 10:15 AMimport com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.future.await
import kotlinx.coroutines.experimental.launch
import java.lang.Thread.sleep
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
class KotlinCache<K, V>(val loader: suspend (K) -> V) {
private val cacheImpl: Cache<K, CompletableFuture<V>> = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.DAYS)
.maximumSize(50)
.build();
suspend fun get(key: K): V {
var thisInvocationShouldCompleteFuture = false // it will be true this invokation should schedule loader evalution
val futureResult = cacheImpl.get(key, {
thisInvocationShouldCompleteFuture = true;
CompletableFuture()
})
if (thisInvocationShouldCompleteFuture) {
try {
val result = loader(key)
futureResult.complete(result)
return result;
} catch (t: Throwable) {
futureResult.completeExceptionally(t);
cacheImpl.invalidate(key)
throw t
}
} else {
return futureResult.await()
}
}
}