rrva
03/25/2020, 1:19 PMSam Garfinkel
03/25/2020, 2:24 PMDeferred
in the cache as Deferred
is a coroutine-safe data structure (via suspendable await
). However directly manipulating a cache from a coroutine is likely unsafe. Note though that calling await
on an already complete Deferred<T>
is free and trivially returns the underlying T
.rrva
03/25/2020, 7:50 PMclass FooCoroutinesClient(private val fooUrl: String, val userAgent: String) {
val coroutineScope = CoroutineScope(Dispatchers.Default)
private val cache: LoadingCache<String, Deferred<FooResponse>> =
Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(30, TimeUnit.SECONDS)
.build { key -> coroutineScope.async { doFetchFoo(key) } }
val client = HttpClient(Apache) {
engine {
connectionRequestTimeout = 400
}
install(HttpTimeout){
connectTimeoutMillis = 400
socketTimeoutMillis = 100
}
install(JsonFeature) {
serializer = KotlinxSerializer(
Json(
JsonConfiguration(
isLenient = true,
ignoreUnknownKeys = true,
serializeSpecialFloatingPointValues = true,
useArrayPolymorphism = true
)
)
)
}
}
suspend fun doFetchFoo(query: String): FooResponse {
return client.request {
header("User-Agent", userAgent)
parameter("query", query)
url("$fooUrl/v1/foo")
}
}
suspend fun fetchFoo(query: String): FooResponse {
return cache.get(query)?.await()!!
}
}
Sam Garfinkel
03/31/2020, 6:03 PMsuspend fun doFetchFoo
should definitely be private and only called from fetchQuery
.