I use JSR 107 JCache in GAE to temporarily store data captured from web and write it to datastore at certain interval (10 mins). My app only use one cache. Most of the time it works well. Once in a while (5-6 times out of 4,000 per day) one of the entries in the cache got missing due to unknown reason. I am not very faimilar with JCache but I somehow understand my app may run at different JVM instance and different JCache instance may be used by my app.
The problem can be found in the log below:
2013-12-31 09:58:14.229 /cron/<myservlet>?code=11 200 ........... app_engine_release=1.8.8 instance=00c61b117c1599a88baa456ae838cbfa9b0f28
2013-12-31 09:58:14.011 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.117 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.121 <myapp>.RealCache get: Cache 11 has ...... <expected result>......
2013-12-31 09:58:14.121 cron.<myservlet> doGet: Appended with <mydata> for 11
2013-12-31 09:58:14.121 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.224 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.443 /cron/<myservlet>?code=6 200 ............ app_engine_release=1.8.8 instance=00c61b117c1599a88baa456ae838cbfa9b0f28
2013-12-31 09:58:14.227 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.326 <myapp>.RealCache validate: Cache contains 0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13,
2013-12-31 09:58:14.329 <myapp>.RealCache get: Cache 6 has ..... <expected result>......
2013-12-31 09:58:14.329 cron.<myservlet> doGet: Appended with <mydata> for 6
2013-12-31 09:58:14.329 <myapp>.RealCache validate: realCache 29829270 retrieved
2013-12-31 09:58:14.437 <myapp>.RealCache validate: Cache contains 0, 2, 3, 4, 5, 6, 8, 11, 12, 13,
These are 2 executions of my servlet. As you can see, they run only 0.2 sec apart and on same GAE instance. "Cache contains 0-13" is the key of the Map in realCache. "realCache 29829270 retrieved" is the hashcode of the Cache I use. There are two of them, one is logged when I get() the cache, another one when I put(). You can see that in the second execution, the "Cache contains ..." are different in get() and put(), the key "1" is missing. These two executions were run ok because the missing key "1" is not involved. But problem appeared in a later execution when "code=1" where the previously accummulated data for "1" is missing. You can see what I want to do and my problem in the coding below.
Here are my coding (logging code skipped for simplicity):
public class RealCache {
private static Cache realCache;
public static synchronized void validate() {
realCache = CacheManager.getInstance().getCache(Constants.Whale);
if (realCache == null) { //for first time of the day
CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
Map<String, Integer> props = new HashMap<>();
props.put(GCacheFactory.EXPIRATION_DELTA, 28800); //8 hrs is enough
realCache = cacheFactory.createCache(Collections.emptyMap());
CacheManager.getInstance().registerCache(Constants.Whale, realCache);
}
}//end validate
public static synchronized MyObj get(int code) {
validate();
MyObj myObj = (MyObj) realCache.get(code);
return myObj;
}//end get
public static synchronized void put(int code, MyObj myObj) {
validate();
realCache.put(code, myObj);
}//end put
}//end RealCache
Here is the code when I use RealCache:
synchronized ("RealCache") {
MyObj myObj = RealCache.get(code);
if (myObj != null) {
myObj.setData(myObj.getData() + newData);
log.info("Appended with "+ newData+ " for "+ code);
} else {
myObj = new MyObj();
myObj.setData(newData);
log.warning("Created with "+ newData+ " for "+ code);
}
RealCache.put(code, myObj);
}//end sync
Please advise what's wrong with my coding.
You should do some reading of various docs on appengine. JCache is a standard cache api implementation that on appengine utilises memcache. See the first line of the docs for JCache on appengine https://developers.google.com/appengine/docs/java/memcache/usingjcache .
Memcache on appengine has no guarantee of entries surviving in the cache. They can be evicted at any time and with not notice. Please read up on memcache behaviour on appengine.
Specifically google states - "In general, an application should not expect a cached value to always be available." https://developers.google.com/appengine/docs/python/memcache/