Fork me on GitHub
Showing posts with label caching. Show all posts
Showing posts with label caching. Show all posts

5 Mar 2010

Page fragment caching with Grails Springcache plugin

Yesterday I released the new version of the Springcache plugin for Grails. The new feature this brings to the table is page fragment caching driven by annotations on controller actions. The feature is based on EhCache Web and is even simpler and more powerful than the full page caching I blogged about recently. With the page fragment caching feature you can:

  • Define @Cacheable and @CacheFlush annotations on controller actions.
  • Have SiteMesh decorate cached and uncached output alike.
  • Use SiteMesh to mix dynamic page sections with cached sections.
  • Use SiteMesh and <g:include> to have multiple areas of the page that are cached and flushed independently of one another.
  • Cache the output of controller actions that use content negotiation separately according to the requested format.

There are some examples in the plugin documentation and the plugin source code has a test project with a variety of page fragment caching mechanisms used and tested.

23 Feb 2010

Full page caching in Grails with Ehcache-Web

I'm on the verge of releasing a new version of the Springcache plugin that will feature a pretty cool new annotation-driven page fragment caching feature based on Ehcache-web. However one of the things that came up during discussions on the mailing list was full page caching. I mentioned that it was pretty straightforward and promised to blog about how to do it, so…

Install Ehcache-web

Add the following to your dependencies in BuildConfig.groovy:
runtime("net.sf.ehcache:ehcache-web:2.0.0") {
 excludes "ehcache-core"
}

Install Grails templates

Run: grails install-templates

Set up a page caching filter

Edit src/templates/war/web.xml and add this to the filters section:
<filter>
 <filter-name>MyPageCachingFilter</filter-name>
 <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
 <init-param>
  <param-name>cacheName</param-name>
  <param-value>myPageCache</param-value>
 </init-param>
</filter>
And this as the first entry in the filter-mappings section:
<filter-mapping>
 <filter-name>MyPageCachingFilter</filter-name>
 <url-pattern>/controller/action/*</url-pattern>
 <dispatcher>REQUEST</dispatcher>
</filter-mapping>

Configure the cache

Unfortunately you can't configure the cache in grails-app/conf/spring/resources.groovy using EhCacheFactoryBean instances as the servlet filter initialises before the Spring context. The cache definitions need to be added to a ehcache.xml which would normally be placed in grails-app/conf. Here is an example that works for the filter definitions above:
<ehcache>

    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10"
            eternal="false"
            timeToIdleSeconds="5"
            timeToLiveSeconds="10"
            overflowToDisk="true"
            />

    <cache name="myPageCache"
           maxElementsInMemory="10"
           eternal="false"
           timeToIdleSeconds="10000"
           timeToLiveSeconds="10000"
           overflowToDisk="true">
    </cache>

</ehcache>

You will need to add another filter and filter-mapping and potentially another cache for each URL pattern you want to cache separately.

Full page caching is fine for simple pages but isn't as flexible as fragment caching. For example, any authenticated state (such as a "Welcome back xxx" label) on the page would get cached across all users. Because Grails uses Sitemesh and has the <g:include> tag for including output from other controllers a fragment caching solution is a good fit. The 1.2 release of the Springcache plugin will add fragment caching functionality. However, I can imagine using full-page caching like this for things like RSS feeds.

12 Dec 2009

New Springcache Plugin Version

After saying it might take me a while I got stuck in and rewrote the Springcache plugin from scratch. The new version is up now. The plugin now requires Grails 1.2.0-M3 or greater as it's reliant on Spring 3.0.

The plugin allows you to declare caching and flushing behaviour on service methods (well, any Spring bean methods, but services are typical) using @Cacheable and @CacheFlush annotations. This is really useful for service methods that perform long-running or expensive tasks such as retrieving data from web services, network resources, etc. The plugin is less appropriate for service methods that retrieve data using GORM/Hibernate as you could just use the 2nd level cache, although there's nothing stopping you doing so if it makes sense in your domain.

The documentation and source code are in the usual places. Here's a quick summary of the changes and new features:

  • No longer depends on the (discontinued and non-Spring 3 compatible) spring-modules-cache library.
  • No more mapcache, the plugin now uses ehcache by default.
  • Only ehcache is supported directly but it's really easy to implement an adapter for other caching libraries if you need to.
  • Slightly simplified configuration. Some minor tweaks will be needed if you're upgrading from an earlier version of the plugin.
  • Bean names are now prefixed with "springcache" so they're much less likely to clash with other things in your Spring context.

There has been some interest in some new features such as a taglib for caching chunks of views which I may start looking at shortly.

26 Nov 2009

Springcache Plugin Status

A couple of people have asked me about the Springcache plugin and Grails 1.2. Currently the plugin is not compatible with 1.2-M3 and onwards. The reason for this is that the spring-modules-cache library that the plugin depends on is not compatible with Spring 3.0 which is used by the newest versions of Grails. Not only that but the spring-modules project has been discontinued altogether. There is a fork of it on Github but that doesn't look terribly active either. This means that at some point I'm going to have to sit down and write some code to bring the annotation driven caching inside the plugin itself and drop the spring-modules dependency. However, just to compound things the Spring documentation on the relevant area hasn't been updated yet and still references the classes that have been removed from the API which is what's causing the incompatibility in the first place!

So, it's on my to-do list but don't hold your breath!

2 Mar 2009

Why would I ever want to disable the L2 cache?

This question came up when pairing last week. We were going through our code-base adding the cache directive to a bunch of our domain classes. Grails is all about sensible defaults and it seems slightly odd that the level 2 cache is configured by default in DataSource.groovy but not actually used unless cache(true) is added to the mapping closure in each domain class. I wonder if anyone has any ideas why it might ever be a bad idea to use the L2 cache?

The only scenario I can come up with is situations where updates are made direct to the DB, bypassing Hibernate. This is, I would think, pretty rare (we do it for some rather naïve hit tracking and for voting on polls). Sure, in this circumstance the L2 cache will likely give you stale results. However, it's very much the exception rather than the rule.

Most other objections I've heard have been some variety of worry about caches eating up vast amounts of heap space and crashing the JVM (which is why cache implementations like ehcache use time-based and LRU eviction).

Oh, and yeah, we did have some issues with our changes but most seem to be to do with cruft and tech debt in our code (mostly now-redundant workarounds to GORM issues from older releases of Grails).