2013-02-12 13 views
10

Ho una semplice applicazione Grails che deve effettuare una chiamata periodica a un servizio Web esterno più volte durante la sessione di un utente (mentre si usa l'interfaccia).La migliore strategia per memorizzare una costosa chiamata al servizio web in Grails

Vorrei memorizzare nella cache questa risposta al servizio web, ma i risultati del servizio cambiano ogni pochi giorni, quindi mi piacerebbe memorizzarlo nella cache per un breve periodo (aggiornamenti giornalieri).

Il plug-in della cache di Grails non sembra supportare le implementazioni "time to live", quindi ho esplorato alcune possibili soluzioni. Mi piacerebbe sapere quale plugin o soluzione programmatica sarebbe meglio risolvere questo problema.

Esempio:

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

C'erano molte buone opzioni. Ho deciso di seguire l'approccio plug-in suggerito da Burt. Ho incluso una risposta esemplificativa con piccole modifiche al precedente esempio di codice per aiutare gli altri a voler fare qualcosa di simile. Questa configurazione espira la cache dopo 24 ore.

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' 
    } 
} 
+0

Utilizzando il plug-in di cache più recente, non è possibile espirarlo: "Poiché non esiste alcun modo per configurare" time to live "con questo plug-in, tutti gli elementi memorizzati nella cache non hanno timeout e rimangono memorizzati nella cache fino al riavvio della JVM (dal momento backing store è in-memory) o la cache è parzialmente o completamente cancellata (chiamando un metodo o un'azione annotata con @CacheEvict o programmaticamente). " – Gregg

+0

Detto questo, potresti avere un cron job che colpisce un servizio web che usa @CacheEvict. È un lavoro in giro, almeno. – Gregg

+1

Sì, ho considerato questo approccio. Per fare un passo in più, Quartz potrebbe sostituire cron per mantenere tutto all'interno dell'applicazione. Spero che il plugin cache abbia funzionato più come il plug-in della cache di primavera. – arcdegree

risposta

0

Dai test di unità grails-cache (cercare timeToLiveSeconds), vedo che è possibile configurare la cache a livello di cache , non per chiamata al metodo o simile. Utilizzando questo metodo, si configureranno le impostazioni per grails.cache.config.

Si crea una cache dedicata con le impostazioni time-to-live e quindi si fa riferimento al servizio.

+0

Sì, questo è un modo che ho trovato per farlo, tuttavia questo plugin è deprecato. Dalla documentazione: "Questo plugin non è più gestito, è stato sostituito dal plugin Cache, sviluppato e supportato da SpringSource." – arcdegree

+0

Credo che i test stiano effettivamente configurando la configurazione che non è supportata, come parte del test. –

1

Un hack/soluzione sarebbe quella di utilizzare una combinazione di @Cacheable ("itemsCache") e @CacheFlush ("itemsCache").

Comunica al metodo getItems() di memorizzare nella cache i risultati.

@Cacheable("itemsCache") 
def getItems() { 
} 

e quindi un altro metodo di servizio per svuotare la cache, che è possibile chiamare frequentemente da un lavoro.

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

Dopo diverse ore di fallimenti in battaglie con SpEL ho vinto la guerra alla fine! Quindi, come sapete, la cache di Grails non ha TTL pronto all'uso. È possibile attenersi a ehcache e fare qualche configurazione di fantasia. O peggio aggiungere la logica vampate di calore sul salvataggio/aggiornamento ecc Ma la mia soluzione è:

@Cacheable(value = 'domainInstance', key="#someId.concat((new java.util.GregorianCalendar().getTimeInMillis()/10000))") 
def getSomeStuffOfDb(String someId){ 
     //extract something of db 
    }  
} 

e una cosa da sottolineare. Puoi saltare la configurazione in Config.groovy e verrà creata e aggiunta automaticamente. Tuttavia, se la tua app è in fase di caricamento subito dopo l'avvio, verranno generate alcune eccezioni.

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: 

quindi per evitare che si prega di aggiungere la configurazione così le strutture della cache saranno pronte in anticipo.

grails.cache.enabled = true 
grails.cache.clearAtStartup = true 
grails.cache.config = { 
    defaults { 
     maxElementsInMemory 10000 
     overflowToDisk false 
    } 
    cache { 
     name 'domainInstance' 
    } 
} 

GregorianCalendar(). GetTimeInMillis()/10000 farà TTL ~ 10sec./1000 ~ 1 sec. Pura matematica qui.

Problemi correlati