I am using ff4j-spring-boot-starter
with f4j-store-springjdbc
to setup my ff4j server. All my other microservices use the endpoints given by ff4j to access this feature store and the response is returned in JSON.
Since the data does not change that often and we are trying to save unnecessary database calls, I am trying to cache my feature store on the server. Also, if the feature flag DB is down (for refresh/maintenance) we still want the other services to successfully start-up using these values from the cache.
We imported ff4j-store-ehcache
in our pom.xml
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC2</spring-cloud.version>
<ff4j.version>1.8.7</ff4j.version>
<odbc.version>19.6.0.0.0</odbc.version>
</properties>
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-spring-boot-starter</artifactId>
<version>${ff4j.version}</version>
</dependency>
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-store-springjdbc</artifactId>
<version>${ff4j.version}</version>
</dependency>
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-web</artifactId>
<version>${ff4j.version}</version>
</dependency>
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-store-ehcache</artifactId>
<version>${ff4j.version}</version>
</dependency>
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-webapi-jersey2x</artifactId>
<version>1.8.11</version>
</dependency>
<!-- FF4J dependencies - end -->
Our FeatureCacheProviderEhCache implementation looks like this in FF4jConfig.java looks like this.
@ConditionalOnClass({ ConsoleServlet.class, FF4jDispatcherServlet.class })
public class Ff4jConfig extends SpringBootServletInitializer {
@Autowired
private DataSource dataSource;
@Bean
public ServletRegistrationBean<FF4jDispatcherServlet> ff4jDispatcherServletRegistrationBean(
FF4jDispatcherServlet ff4jDispatcherServlet) {
ServletRegistrationBean<FF4jDispatcherServlet> bean = new ServletRegistrationBean<FF4jDispatcherServlet>(
ff4jDispatcherServlet, "/web-console/*");
bean.setName("ff4j-console");
bean.setLoadOnStartup(1);
return bean;
}
@Bean
@ConditionalOnMissingBean
public FF4jDispatcherServlet getFF4jDispatcherServlet() {
FF4jDispatcherServlet ff4jConsoleServlet = new FF4jDispatcherServlet();
ff4jConsoleServlet.setFf4j(getFF4j());
return ff4jConsoleServlet;
}
@Bean
public FF4j getFF4j() {
FF4j ff4j = new FF4j();
FF4JCacheManager cacheManager = new FeatureCacheProviderEhCache();
ff4j.setPropertiesStore(new PropertyStoreSpringJdbc(dataSource));
ff4j.setFeatureStore(new FeatureStoreSpringJdbc(dataSource));
ff4j.setEventRepository(new EventRepositorySpringJdbc(dataSource));
ff4j.cache(cacheManager);
// Enable audit mode
ff4j.audit(true);
return ff4j;
}
}
WebConsole reflects the database changes as soon as they are commit and it does not seem like the cache is being hit or that the cache is storing any of the data in it.
I want to be able to use this cache without going to database for every single lookup.
We also tried using InMemoryCacheManager as an alternate to FeatureCacheProviderEhCache, but same results. We do see the clear cache button on our web-console in both the implementations.
Also, is there a better way for me to test if my api calls are actually getting data from cache and not from db, without having to shutdown the db?
Update :
After implementing our own FeatureCacheProviderEhCache, and logging in it,
I tried to access the api/ff4j and the featureNames
is coming in as empty in that response.
Please refer to the log :
METHOD=getCacheFeatures, LINENO=160, MSG=getCacheFeatures :: [ name = ff4jCacheFeatures status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 10000 maxEntriesLocalDisk = 10000000 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 120 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: ; orderedCacheEventListeners: maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
METHOD=listCachedFeatureNames, LINENO=59, MSG=listCachedFeatureNames[]
METHOD=getCacheFeatures, LINENO=160, MSG=getCacheFeatures :: [ name = ff4jCacheFeatures status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 10000 maxEntriesLocalDisk = 10000000 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 120 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: ; orderedCacheEventListeners: maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
The cache is created but it is not storing any values inside it. I am setting the cache the way it says in the first answer.
I the logs, when I print listCachedFeatures(), that is printing as empty as well.
I am still not able to see featureNames
in the cache. Which part am I not configuring correctly?