Pracuję w projekcie uruchamiania w Kotlinie i wiosennym i próbuję użyć kofeiny do buforowania. Mam usługę z zawieszeniem funkcji, która tworzy połączenie HTTP. Oto moja konfiguracja:

@Bean
open fun caffeineConfig(): @NonNull Caffeine<Any, Any> {
   return Caffeine.newBuilder().expireAfterWrite(60, TimeUnit.SECONDS)
}

@Bean
open fun cacheManager(caffeine: Caffeine<Any, Any>): CacheManager {
    val caffeineCacheManager = CaffeineCacheManager()
    caffeineCacheManager.getCache("test")
    caffeineCacheManager.setCaffeine(caffeine)
    return caffeineCacheManager
}

I oto funkcja, którą chcę pamięć:

@Cacheable(value = ["test"])
open suspend fun getString(id: String): String {
    return client.getString(id)
}

Wydaje się jednak, że buforowanie nie działa, ponieważ widzę z dzienników, że klient zostanie nazwany za każdym razem, gdy zostanie wywołana funkcja serwisowa. Czy @Cacheable nie działa dla funkcji zawieszenia? Czy brakuje mi czegoś innego?

1
jojo 15 październik 2020, 16:26

1 odpowiedź

Najlepsza odpowiedź

Dokumentacja @Cacheable mówi:

Za każdym razem, gdy wywołana jest zalecana metoda, zastosowano zachowanie buforowania, sprawdzanie, czy metoda została już wywołana dla danych argumentów. Rozsądne domyślne domyślne wykorzystuje parametry metody do obliczenia klucza, ale wyrażenie spel można dostarczyć za pomocą atrybutu klucza () lub niestandardowej implementacji keygenerator może zastąpić domyślny (patrz KeyGenerator ()).

Modyfikator suspend wstawia parametr {X1}} w wygenerowanym kodzie, który akceptuje wejście od dzwoniącego. To prawdopodobnie oznacza każde wywołanie posiada własną kontynuację, a pamięć podręczna wykrywa to jako wyjątkowe połączenie.

Jednak ponieważ wartość powrotu zostanie również zmieniona w zależności od kontynuacji nie można mieć pamięci podręcznej ignorowania parametru kontynuacji. Lepszym podejściem jest nie używać funkcji suspend i zamiast tego zwrócić Deferred, które konsumenci mogą dzielić:

@Cacheable(value = ["test"])
open fun getString(id: String): Deferred<String> {
    return someScope.async {
        client.getString(id)
    }
}

// Consumer side
getString(id).await()

Powinno to działać ze standardowym mechanizmem buforowania, ponieważ Deferred jest normalnym obiektem i nie są wymagane żadne specjalne parametry.

1
Kiskae 15 październik 2020, 13:53