Caching 在Grails中缓存昂贵web服务调用的最佳策略

Caching 在Grails中缓存昂贵web服务调用的最佳策略,caching,grails,Caching,Grails,我有一个简单的Grails应用程序,它需要在用户会话期间(在用户使用接口时)多次定期调用外部web服务 我希望缓存此web服务响应,但服务的结果大约每隔几天就会更改一次,因此我希望将其缓存一段时间(可能是每天刷新) Grails缓存插件似乎不支持“生存时间”实现,因此我一直在探索一些可能的解决方案。我想知道什么插件或编程解决方案最能解决这个问题 例如: BuildConfig.groovy plugins{ compile ':cache:1.0.0' } def getItems()

我有一个简单的Grails应用程序,它需要在用户会话期间(在用户使用接口时)多次定期调用外部web服务

我希望缓存此web服务响应,但服务的结果大约每隔几天就会更改一次,因此我希望将其缓存一段时间(可能是每天刷新)

Grails缓存插件似乎不支持“生存时间”实现,因此我一直在探索一些可能的解决方案。我想知道什么插件或编程解决方案最能解决这个问题

例如:

BuildConfig.groovy

plugins{
    compile ':cache:1.0.0'
}
def getItems(){
    def items = MyService.getItems()
    [items: items]
}
@Cacheable("itemsCache")
class MyService {
    def getItems() {
        def results

        //expensive external web service call

        return results
    }
}
plugins{
    compile ':cache:1.1.7'
    compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 86400
        timeToLiveSeconds 86400
        overflowToDisk false
        maxElementsOnDisk 0
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU'
     }
 }
MyController.groovy

plugins{
    compile ':cache:1.0.0'
}
def getItems(){
    def items = MyService.getItems()
    [items: items]
}
@Cacheable("itemsCache")
class MyService {
    def getItems() {
        def results

        //expensive external web service call

        return results
    }
}
plugins{
    compile ':cache:1.1.7'
    compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 86400
        timeToLiveSeconds 86400
        overflowToDisk false
        maxElementsOnDisk 0
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU'
     }
 }
MyService.groovy

plugins{
    compile ':cache:1.0.0'
}
def getItems(){
    def items = MyService.getItems()
    [items: items]
}
@Cacheable("itemsCache")
class MyService {
    def getItems() {
        def results

        //expensive external web service call

        return results
    }
}
plugins{
    compile ':cache:1.1.7'
    compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 86400
        timeToLiveSeconds 86400
        overflowToDisk false
        maxElementsOnDisk 0
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU'
     }
 }
更新

有很多好的选择。我决定采用伯特建议的插件方法。我已经包括了一个示例答案,上面的代码示例有一些小的改动,以帮助其他想要做类似事情的人。此配置将在24小时后使缓存过期

BuildConfig.groovy

plugins{
    compile ':cache:1.0.0'
}
def getItems(){
    def items = MyService.getItems()
    [items: items]
}
@Cacheable("itemsCache")
class MyService {
    def getItems() {
        def results

        //expensive external web service call

        return results
    }
}
plugins{
    compile ':cache:1.1.7'
    compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 86400
        timeToLiveSeconds 86400
        overflowToDisk false
        maxElementsOnDisk 0
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU'
     }
 }
Config.groovy

plugins{
    compile ':cache:1.0.0'
}
def getItems(){
    def items = MyService.getItems()
    [items: items]
}
@Cacheable("itemsCache")
class MyService {
    def getItems() {
        def results

        //expensive external web service call

        return results
    }
}
plugins{
    compile ':cache:1.1.7'
    compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 86400
        timeToLiveSeconds 86400
        overflowToDisk false
        maxElementsOnDisk 0
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU'
     }
 }
通过单元测试(查找timeToLiveSeconds),我发现您可以在缓存级别配置缓存,而不是每个方法调用或类似的配置。使用此方法,可以配置grails.cache.config的设置


您可以使用time to live设置创建一个专用缓存,然后在服务中引用它。

核心插件不支持TTL,但Ehcache插件支持TTL。看


该插件依赖于缓存管理器,但将其替换为使用Ehcache的缓存管理器(因此您需要同时安装两者)

一个黑客/解决方法是使用@Cacheable(“itemsCache”)和@CacheFlush(“itemsCache”)的组合

告诉getItems()方法缓存结果

@Cacheable("itemsCache")
def getItems() {
}
然后使用另一种服务方法刷新缓存,您可以从作业中频繁调用缓存

@CacheFlush("itemsCache")
def flushItemsCache() {}

在与斯佩尔的几小时战斗失败后,我终于赢得了这场战争! 因此,正如您所知,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秒。这里是纯数学。

是的,这是我发现的一种方法,但是这个插件不受欢迎。从文档中可以看出:“这个插件不再被维护。它已经被SpringSource开发和支持的缓存插件所取代。”我相信测试实际上是在设置不受支持的配置,作为测试的一部分。使用最新的缓存插件,你不能使它过期:“因为没有办法配置”生存时间“使用此插件,所有缓存项都没有超时,并保持缓存状态,直到JVM重新启动(因为备份存储在内存中)或缓存部分或完全清除(通过调用带有@cacheexecute注释的方法或操作或以编程方式)。“这就是说,您可以有一个cron作业,它可以访问使用@cacheexecute的web服务。至少这是一种变通方法。是的,我考虑过这种方法。为了更进一步,Quartz可以取代cron,将所有内容都保存在应用程序中。我希望缓存插件更像spring缓存插件。需要同时安装这两个插件。。救了我一天!