Skip to main content
Blog

Fix CacheManager with same name grails-cache-ehcache

By 15 december 2014januari 30th, 2017No Comments
[box type=”shadow”]Or: “getting parallel deployment to work when using EhCache”[/box]

Caching

During our regular Grails development work, we apply both Hibernate with second level caching and Spring method level caching. They both use EhCache by default. This seems to be the only mature implementation choice for the Grails platform.
All this used to work fine (so we thought) until we wanted to add the Tomcat parallel deployment feature to the mix.

What happened was that we ran into the following error:
Another CacheManager with same name 'grails-cache-ehcache' already exists in the same VM

What does it mean?

Well, it comes down to a combination of libraries and use cases in which things become tricky. Some caching component is trying to start, but somehow it was already found to exist in the running JVM. I’m not going to bore you with specific versions of libraries, but I’ll explain why it matters (you can look them up in the links section at the end of this post).

Hibernate vs. EhCache versions



Caches are everywhere

One of the factors is the Hibernate version combined with an EhCache version, which at some version of EhCache starts requiring a unique name for the cache manager, and it should not exist yet within the VM. An existing cache manager will no longer be recycled. With older versions of EhCache (that come with Hibernate by default) this was not an immediate problem (although it could cause memory problems!, more on that later).

Grails Cache-EhCache plugin version

Another one is the grails cache-ehcache plugin to enable spring method cache using EhCache (because of the awesome TTL feature). It too will require a unique manager name starting from a certain version (for jmx registration).

Tomcat parallel deployment

The final factor is the Tomcat parallel deployment feature. The same application (and version) runs twice in the same VM for a while (until the all the sessions have moved to the new version). This will mean that where the cache manager (name) used to be unique inside the VM, it will no longer be. There will be two instances.

[box type=”shadow”]Do not get confused. A similar error will tell you “Another unnamed CacheManager already exists in the same VM, this is a slightly different problem which usually occurs when hibernate is ran without a context name specified.[/box]

Workarounds

We first started out with workarounds. To have a temporary fix, we just disabled method caches, or if possible went for the naive concurrent hashmap approach (that will eventually eat your entire heap!, but that’s ok for a temporary fix).

A sneaky problem on the side

But we also discovered that PermGen problems will occur if cache managers are not cleared! (or metaspace problems for Java 8). This problem required quite some investigation using visualvm and a lot of painful researching of classloaders and classes.

A solution for using EhCache for both purposes

In short: a unique name, for the cache manager, at each deployment using a timestamp. This will allow using ehCache for both spring method caching and hibernate second level cache. The next question would be, how to implement?

This actually required a minor code change in the cache-ehcache plugin for grails.
The plugin already allowed specifying a custom ‘provider’ name which results in a cache manager name, that can be made unique. This was not enough though. During the initialization phase there was a temporary cache manager instantiated that still uses a fixed name, which would clash.
The cache-ehcache plugin initialization strategy is a bit odd, this leads to the application having to specify the cache manager name twice. The code change makes it possible to also provide a custom name for that temporary instance.

So when using hibernate 4, combine it with ehcache 2.8.2 and using the latest cache-ehcache plugin (1.0.5-SNAPSHOT at the time of writing) an example config (several files) will look like this.

The configuration for this setup (Config.groovy):

grails{
    cache {
        order = 2000 // higher than default (1000) and plugins, usually 1500
        enabled = true
        clearAtStartup=true // reset caches when redeploying
        ehcache {
            // ehcacheXmlLocation = 'classpath:ehcache.xml' // no custom xml config location (no xml at all)
            reloadable = false
        }
    }
}

def uniqueCacheManagerName = appName + "ConfigEhcache-" + System.currentTimeMillis()
 
// customize temp ehcache cache manager name upon startup
grails.cache.ehcache.cacheManagerName = uniqueCacheManagerName
 
grails.cache.config = {
    provider {
        updateCheck false
        monitoring 'on'
        dynamicConfig false
        // unique name when configuring caches
        name uniqueCacheManagerName
    }
    defaultCache {
        maxElementsInMemory 10000
        eternal false
        timeToIdleSeconds 120
        timeToLiveSeconds 120
        overflowToDisk false // no disk use, this would require more config
        maxElementsOnDisk 10000000
        diskPersistent false
        diskExpiryThreadIntervalSeconds 120
        memoryStoreEvictionPolicy 'LRU' // least recently used gets kicked out
    }
}

Configure hibernate properly for second level cache (DataSource.groovy):

hibernate {
// cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' // Hibernate 3
// cache.region.factory_class = 'org.hibernate.cache.ehcache.EhCacheRegionFactory' // Hibernate 4
// cache.region.factory_class = 'grails.plugin.cache.ehcache.hibernate.BeanEhcacheRegionFactory' // For EhCache method caching + Hibernate before 4.0
   cache.region.factory_class = 'grails.plugin.cache.ehcache.hibernate.BeanEhcacheRegionFactory4' // For EhCache method caching + Hibernate 4.0 and higher
}

Libraries (in BuildConfig.groovy):

dependencies {
   compile 'net.sf.ehcache:ehcache:2.8.2'
}
plugins {
   compile ":cache:1.1.8" // a matching version of the general cache plugin for grails
   compile ":cache-ehcache:1.0.5-SNAPSHOT" // latest of the cache-ehcache plugin since it has the code change required
   runtime (":hibernate4:4.3.6.1") {
	excludes "ehcache-core" // prevent the old ehcache version to get into dependencies
   }
}

Maybe add some debugging using the BootStrap.groovy:

def grailsCacheManager // generic grails cache manager (contains ehcache cache manager)
CacheManager ehcacheCacheManager // uses DataSource properties to register mbean
String displayName = ""
 
def init = { servletContext ->
    log.info "================ BootStrap #init ===================="
    log.info "manager name: ${ehcacheCacheManager?.name}"
     
    displayName = servletContext.servletContextName
    log.info "Started application: ${displayName}"
}
 
def destroy = {
    log.info "================ BootStrap #destroy ===================="
     
    log.info "Shut down application: ${displayName}"
}

Having all this setup correctly, caching just works, parallel deploy works and PermGen is freed!

Other benefits:

  • a jmx registration that has the name of the application in it, so you can actually see which cache belongs to whom
  • a timestamp in the name provides direct information on whether the caches are old or new (when cache managers are re-used, it’s hard to tell)

Read more