Disabling Caching at Runtime if Couchbase Connection Failed

In our application we have number of REST API calls out of which some of them are flagged with @Cacheable to cache the response. Cache is backed by Couchbase and whenever application fails to connect Couchbase node then application goes down.

Which is what we are not expecting, we expect data should be served from the source system whenever connection failed, basically bypassing the cache and as soon as the Couchbase node is up or connection established response should be served from cache.

To achieve the same mechanism, I returned “null” whenever connection fails or there is a Cache miss overriding CouchbaseCacheManager, as follows:


import java.util.Map;
import org.springframework.cache.Cache;
import com.couchbase.client.spring.cache.CacheBuilder;
import com.couchbase.client.spring.cache.CouchbaseCacheManager;

public class CouchbaseCustomCacheManager extends CouchbaseCacheManager {

	public CouchbaseCustomCacheManager(final Map<String, CacheBuilder> initialCaches) {
		super(initialCaches);
	}

	@Override
	public Cache getCache(String name) {
		return new CouchbaseCacheWrapper(super.getCache(name));
	}

	protected static class CouchbaseCacheWrapper implements Cache {

		private final Cache delegate;

		public CouchbaseCacheWrapper(Cache couchbaseCache) {
			this.delegate = couchbaseCache;
		}

		@Override
		public String getName() {
			try {
				return delegate.getName();
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public Object getNativeCache() {
			try {
				return delegate.getNativeCache();
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public ValueWrapper get(Object key) {
			try {
				return delegate.get(key);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public <T> T get(Object key, Class<T> type) {
			try {
				return delegate.get(key, type);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public void put(Object key, Object value) {
			try {
				delegate.put(key, value);
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		@Override
		public ValueWrapper putIfAbsent(Object key, Object value) {
			try {
				return delegate.putIfAbsent(key, value);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public void evict(Object key) {
			try {
				delegate.evict(key);
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		@Override
		public void clear() {
			try {
				delegate.clear();
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		protected <T> T handleErrors(Exception e) throws Exception {
			if (e instanceof Exception) {
				return null;
			} else {
				throw e;
			}
		}
	}
}

And used it as CacheManager, as follows:

@Bean
public CacheManager cacheManager() {
	final Map<String, CacheBuilder> cache = new HashMap<>();
	for (final String appCache : "127.0.0.1,127.0.0.2,127.0.0.3".split(",")) {
			cache.put(appCache, CacheBuilder.newInstance(CouchbaseCluster
					.create().openBucket("default", "")));
	}
	return new CouchbaseCustomCacheManager(cache);
}

Complete source is available on github.

Advertisements