How to setup service method caching in grails

1.3k views Asked by At

My application has a couple of services that make external calls via httpClient (GET and POST) that are unlikely to change in months, but they are slow; making my application even slower. Clarification: this is NOT about caching GORM/hibernate/queries to my db.

How can I cache these methods (persistence on disk gets bonus points...) in grails 2.1.0?

I have installed grails-cache-plugin but it doesn't seem to be working, or i configured it wrong (very hard to do since there are 2-5 lines to add only, but i've managed to do it in the past)

I also tried setting up an nginx proxy cache in front of my app, but when i submit one of my forms with slight changes, I get the first submission as result.

Any suggestions/ideas will be greatly appreciated.

EDIT: Current solution (based on Marcin's answer)

My config.groovy: (the caching part only)

//caching
grails.cache.enabled = true
grails.cache.clearAtStartup = false

grails.cache.config = {
    defaults {
        timeToIdleSeconds 3600
        timeToLiveSeconds 2629740
        maxElementsInMemory 1
        eternal false
        overflowToDisk true
        memoryStoreEvictionPolicy 'LRU'
    }

    diskStore {
        path 'cache'
    }

    cache {
        name 'scoring'
    }
    cache {
        name 'query'
    }
}

The important parts are:

  • do not clear at startup (grails.cache.clearAtStartup = false)
  • overflowToDisk=true persists all results over maxElementsInMemory
  • maxElementsInMemory=1 reduced number of elements in memory
  • 'diskStore' should be writable by the user running the app.
3

There are 3 answers

4
Marcin Świerczyński On BEST ANSWER

Grails Cache Plugin works quite well for me under Grails 2.3.11. Documentation is pretty neat, but just to show you a draft...

I use the following settings in Config.groovy:

grails.cache.enabled = true
grails.cache.clearAtStartup = true

grails.cache.config = {
    defaults {
        maxElementsInMemory 10000
        overflowToDisk false
        maxElementsOnDisk 0
        eternal true
        timeToLiveSeconds 0
    }
    cache {
        name 'somecache'
    }
}

Then, in the service I use something like:

@Cacheable(value = 'somecache', key = '#p0.id.toString().concat(#p1)')
def serviceMethod(Domain d, String s) {
    // ...
}

Notice the somecache part is reused. Also, it was important to use String as key in my case. That's why I used toString() on id.

The plugin can be also set up to use disk storage, but I don't use it.

If it doesn't help, please provide more details on your issue.

1
George Smith On

This may not help, but if you upgrade the application to Grails 2.4.x you can use the @Memoize annotation. This will automagically cache the results of each method call based upon the arguments passed into it.

0
Bruno C On

In order to store this "almost static" information you could use Memcached or Redis as a cache system. (There are many others)

This two cache systems allows you to store key-value data (in your case something like this "key_GET": JSON,XML,MAP,String ).

Here is a related post: Memcached vs. Redis?

Regards.