У меня есть серверное приложение Kotlin JVM, использующее сопрограммы, и мне нужно поместить кеш перед неблокирующим сетевым вызовом.Я полагаю, что могу использовать кофеин AsyncLoadingCache
, чтобы получить неблокирующее поведение кэша, которое мне нужно.Интерфейс AsyncCacheLoader
, который мне нужно реализовать, использует CompletableFuture
.Между тем, метод, который я хочу вызвать для загрузки записей кэша, является функцией suspend
.
Я могу сократить разрыв следующим образом:
abstract class SuspendingCacheLoader<K, V>: AsyncCacheLoader<K, V> {
abstract suspend fun load(key: K): V
final override fun asyncLoad(key: K, executor: Executor): CompletableFuture<V> {
return GlobalScope.async(executor.asCoroutineDispatcher()) {
load(key)
}.asCompletableFuture()
}
}
Это запустит load
функция на предоставленном Executor
(по умолчанию ForkJoinPool
), что с точки зрения кофеина является правильным поведением.
Однако я знаю, что должен попытаться избегать использованияGlobalScope для запуска сопрограмм .
Я подумал о том, чтобы SuspendingCacheLoader
реализовал CoroutineScope
и управлял собственным контекстом сопрограмм.Но CoroutineScope
предназначен для реализации объектами с управляемым жизненным циклом.Ни у кеша, ни у AsyncCacheLoader
нет никаких хуков жизненного цикла.Кеш принадлежит экземплярам Executor
и CompletableFuture
, поэтому он уже таким образом контролирует жизненный цикл задач загрузки.Я не вижу, чтобы наличие задач, принадлежащих контексту сопрограммы, могло бы что-то добавить, и я беспокоюсь, что не смогу правильно закрыть контекст сопрограммы после того, как кэш перестал использоваться.
Написание собственного механизма асинхронного кэширования было бы непосильно трудным, поэтому я бы хотел интегрироваться с реализацией Caffeine, если смогу.
Использует ли GlobalScope
правильный подход для реализации AsyncCacheLoader
, или естьлучшее решение?