Лучшая стратегия кэширования дорогого веб-сервиса в Grails
У меня есть простое приложение Grails, которое нужно периодически делать для внешнего веб-сервиса во время сеанса пользователя (при использовании интерфейса).
Я хотел бы кэшировать этот ответ веб-службы, но результаты службы меняются примерно каждые несколько дней, поэтому я хотел бы кэшировать его на короткое время (возможно, ежедневно обновляется).
Плагин кэширования Grails, похоже, не поддерживает реализацию "времени для жизни", поэтому я изучал несколько возможных решений. Я хотел бы знать, какой плагин или программное решение лучше всего решить эту проблему.
Пример:
BuildConfig.groovy
plugins{
compile ':cache:1.0.0'
}
MyController.groovy
def getItems(){
def items = MyService.getItems()
[items: items]
}
MyService.groovy
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
UPDATE
Было много хороших вариантов. Я решил пойти с подходом к плагину, который предложил Берт. Я включил пример ответа с незначительными изменениями в приведенный выше пример кода, чтобы помочь другим, желающим сделать что-то подобное. Эта конфигурация завершает кеш через 24 часа.
BuildConfig.groovy
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
Config.groovy
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
Ответы
Ответ 1
Основной плагин не поддерживает TTL, но плагин Ehcache. См. http://grails-plugins.github.com/grails-cache-ehcache/docs/manual/guide/usage.html#dsl
Плагин http://grails.org/plugin/cache-ehcache зависит от http://grails.org/plugin/cache, но заменяет диспетчер кэша тем, который использует Ehcache (так что вам нужно оба установить)
Ответ 2
Взаимодействие/обходное решение будет заключаться в использовании комбинации @Cacheable ( "itemsCache" ) и @CacheFlush ( "itemsCache" ).
Сообщите метод getItems() для кэширования результатов.
@Cacheable("itemsCache")
def getItems() {
}
а затем еще один метод обслуживания для очистки кеша, который вы часто можете вызывать из задания.
@CacheFlush("itemsCache")
def flushItemsCache() {}
Ответ 3
Из grails-cache модульных тестов (Ищите timeToLiveSeconds), я вижу, что вы можете настроить кеширование на уровне кеша, а не на метод вызова или аналогичного. Используя этот метод, вы должны настроить параметры для grails.cache.config.
Вы создадите выделенный кеш с настройками времени жизни, а затем ссылаетесь на него в своей службе.
Ответ 4
После нескольких часов неудач в боях со SpEL я выиграл войну в конце!
Так как вы знаете, что кэш Grails не имеет TTL из коробки. Вы можете придерживаться ehcache и делать какую-то причудливую конфигурацию. Или, что еще хуже, добавьте логику, очищающую ее при сохранении/обновлении и т.д. Но мое решение:
@Cacheable(value = 'domainInstance', key="#someId.concat((new java.util.GregorianCalendar().getTimeInMillis()/10000))")
def getSomeStuffOfDb(String someId){
//extract something of db
}
}
и еще одно, что нужно указать. Вы можете пропустить конфигурацию в Config.groovy, и она будет создана и автоматически добавлена сама.
Однако, если ваше приложение находится под нагрузкой сразу после запуска, это приведет к некоторым исключениям.
2017-03-02 14:05:53,159 [http-apr-8080-exec-169] ERROR errors.GrailsExceptionResolver - CacheException occurred when processing request: [GET] /some/get
Failed to get lock for campaignInstance cache creation. Stacktrace follows:
поэтому, чтобы избежать этого, добавьте конфигурацию, чтобы средства кэширования были готовы заранее.
grails.cache.enabled = true
grails.cache.clearAtStartup = true
grails.cache.config = {
defaults {
maxElementsInMemory 10000
overflowToDisk false
}
cache {
name 'domainInstance'
}
}
GregorianCalendar(). getTimeInMillis()/10000 сделает TTL ~ 10 сек. /1000 ~ 1 сек. Чистая математика здесь.