FINERACT-2262: Improve cache handling and add customization option
This commit is contained in:
@@ -247,5 +247,7 @@ dependencyManagement {
|
|||||||
dependency 'io.cucumber:cucumber-java8:7.20.1'
|
dependency 'io.cucumber:cucumber-java8:7.20.1'
|
||||||
dependency 'io.cucumber:cucumber-junit-platform-engine:7.20.1'
|
dependency 'io.cucumber:cucumber-junit-platform-engine:7.20.1'
|
||||||
dependency 'io.cucumber:cucumber-spring:7.20.1'
|
dependency 'io.cucumber:cucumber-spring:7.20.1'
|
||||||
|
|
||||||
|
dependency 'org.reflections:reflections:0.10.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.fineract.infrastructure.core.config;
|
package org.apache.fineract.infrastructure.core.config;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -81,6 +82,8 @@ public class FineractProperties {
|
|||||||
|
|
||||||
private FineractSqlValidationProperties sqlValidation;
|
private FineractSqlValidationProperties sqlValidation;
|
||||||
|
|
||||||
|
private FineractCache cache;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public static class FineractTenantProperties {
|
public static class FineractTenantProperties {
|
||||||
@@ -578,4 +581,20 @@ public class FineractProperties {
|
|||||||
private String name;
|
private String name;
|
||||||
private String pattern;
|
private String pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class FineractCache {
|
||||||
|
|
||||||
|
private FineractCacheDetails defaultTemplate;
|
||||||
|
private Map<String, FineractCacheDetails> customTemplates = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class FineractCacheDetails {
|
||||||
|
|
||||||
|
private Duration ttl;
|
||||||
|
private Integer maximumEntries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ dependencies {
|
|||||||
'org.mapstruct:mapstruct',
|
'org.mapstruct:mapstruct',
|
||||||
|
|
||||||
'io.github.resilience4j:resilience4j-spring-boot3',
|
'io.github.resilience4j:resilience4j-spring-boot3',
|
||||||
|
'org.reflections:reflections',
|
||||||
)
|
)
|
||||||
|
|
||||||
implementation 'software.amazon.msk:aws-msk-iam-auth'
|
implementation 'software.amazon.msk:aws-msk-iam-auth'
|
||||||
|
|||||||
+60
-56
@@ -19,23 +19,38 @@
|
|||||||
|
|
||||||
package org.apache.fineract.infrastructure.core.config.cache;
|
package org.apache.fineract.infrastructure.core.config.cache;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.cache.CacheManager;
|
import javax.cache.CacheManager;
|
||||||
import javax.cache.Caching;
|
import javax.cache.Caching;
|
||||||
import javax.cache.spi.CachingProvider;
|
import javax.cache.spi.CachingProvider;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
||||||
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
||||||
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
||||||
import org.ehcache.jsr107.Eh107Configuration;
|
import org.ehcache.jsr107.Eh107Configuration;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
import org.reflections.scanners.Scanners;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.cache.jcache.JCacheCacheManager;
|
import org.springframework.cache.jcache.JCacheCacheManager;
|
||||||
import org.springframework.cache.support.NoOpCacheManager;
|
import org.springframework.cache.support.NoOpCacheManager;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
public class CacheConfig {
|
public class CacheConfig {
|
||||||
|
|
||||||
public static final String CONFIG_BY_NAME_CACHE_NAME = "configByName";
|
public static final String CONFIG_BY_NAME_CACHE_NAME = "configByName";
|
||||||
|
@Autowired
|
||||||
|
private FineractProperties fineractProperties;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public TransactionBoundCacheManager defaultCacheManager(JCacheCacheManager ehCacheManager) {
|
public TransactionBoundCacheManager defaultCacheManager(JCacheCacheManager ehCacheManager) {
|
||||||
@@ -56,63 +71,52 @@ public class CacheConfig {
|
|||||||
private CacheManager getInternalEhCacheManager() {
|
private CacheManager getInternalEhCacheManager() {
|
||||||
CachingProvider provider = Caching.getCachingProvider();
|
CachingProvider provider = Caching.getCachingProvider();
|
||||||
CacheManager cacheManager = provider.getCacheManager();
|
CacheManager cacheManager = provider.getCacheManager();
|
||||||
|
// Default cache configuration template
|
||||||
javax.cache.configuration.Configuration<Object, Object> defaultTemplate = Eh107Configuration.fromEhcacheCacheConfiguration(
|
Duration defaultTimeToLive = fineractProperties.getCache().getDefaultTemplate().getTtl();
|
||||||
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(10000))
|
Integer defaultMaxEntries = fineractProperties.getCache().getDefaultTemplate().getMaximumEntries();
|
||||||
.withExpiry(ExpiryPolicyBuilder.noExpiration()).build());
|
javax.cache.configuration.Configuration<Object, Object> defaultTemplate = generateCacheConfiguration(defaultMaxEntries,
|
||||||
|
defaultTimeToLive);
|
||||||
if (cacheManager.getCache("users") == null) {
|
// Scan all packages (entire classpath)
|
||||||
cacheManager.createCache("users", defaultTemplate);
|
Reflections reflections = new Reflections(
|
||||||
|
new org.reflections.util.ConfigurationBuilder().forPackages("").addScanners(Scanners.MethodsAnnotated));
|
||||||
|
// Find all methods annotated with @Cacheable
|
||||||
|
Set<Method> annotatedMethods = reflections.getMethodsAnnotatedWith(Cacheable.class);
|
||||||
|
Set<String> cacheNames = annotatedMethods.stream().map(method -> method.getAnnotation(Cacheable.class))
|
||||||
|
.flatMap(annotation -> Arrays.stream(annotation.value())).collect(Collectors.toSet());
|
||||||
|
// Register the caches into the cache manager
|
||||||
|
cacheNames.forEach(cacheName -> {
|
||||||
|
if (cacheManager.getCache(cacheName) == null) {
|
||||||
|
javax.cache.configuration.Configuration<Object, Object> configurationTemplate = generateCustomCacheConfiguration(cacheName,
|
||||||
|
defaultTemplate, defaultTimeToLive, defaultMaxEntries);
|
||||||
|
cacheManager.createCache(cacheName, configurationTemplate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Set<String> incorrectConfigurations = new HashSet<>(fineractProperties.getCache().getCustomTemplates().keySet());
|
||||||
|
incorrectConfigurations.removeAll(cacheNames);
|
||||||
|
if (!incorrectConfigurations.isEmpty()) {
|
||||||
|
log.warn("The following cache configurations are defined but cache does not exists: {}", incorrectConfigurations);
|
||||||
}
|
}
|
||||||
if (cacheManager.getCache("usersByUsername") == null) {
|
|
||||||
cacheManager.createCache("usersByUsername", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("tenantsById") == null) {
|
|
||||||
cacheManager.createCache("tenantsById", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("offices") == null) {
|
|
||||||
cacheManager.createCache("offices", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("officesForDropdown") == null) {
|
|
||||||
cacheManager.createCache("officesForDropdown", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("officesById") == null) {
|
|
||||||
cacheManager.createCache("officesById", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("charges") == null) {
|
|
||||||
cacheManager.createCache("charges", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("funds") == null) {
|
|
||||||
cacheManager.createCache("funds", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("code_values") == null) {
|
|
||||||
cacheManager.createCache("code_values", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("codes") == null) {
|
|
||||||
cacheManager.createCache("codes", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("hooks") == null) {
|
|
||||||
cacheManager.createCache("hooks", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache("tfConfig") == null) {
|
|
||||||
cacheManager.createCache("tfConfig", defaultTemplate);
|
|
||||||
}
|
|
||||||
if (cacheManager.getCache(CONFIG_BY_NAME_CACHE_NAME) == null) {
|
|
||||||
cacheManager.createCache(CONFIG_BY_NAME_CACHE_NAME, defaultTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
javax.cache.configuration.Configuration<Object, Object> accessTokenTemplate = Eh107Configuration.fromEhcacheCacheConfiguration(
|
|
||||||
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(10000))
|
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(2))).build());
|
|
||||||
|
|
||||||
if (cacheManager.getCache("userTFAccessToken") == null) {
|
|
||||||
cacheManager.createCache("userTFAccessToken", accessTokenTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cacheManager.getCache("payment_types") == null) {
|
|
||||||
cacheManager.createCache("payment_types", defaultTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cacheManager;
|
return cacheManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private javax.cache.configuration.Configuration<Object, Object> generateCustomCacheConfiguration(String cacheIdentifier,
|
||||||
|
javax.cache.configuration.Configuration<Object, Object> defaultTemplate, Duration defaultTimeToLive,
|
||||||
|
Integer defaultMaxEntries) {
|
||||||
|
javax.cache.configuration.Configuration<Object, Object> configurationTemplate = defaultTemplate;
|
||||||
|
if (fineractProperties.getCache().getCustomTemplates().containsKey(cacheIdentifier)) {
|
||||||
|
Duration timeToLiveExpiration = Objects.requireNonNullElse(
|
||||||
|
fineractProperties.getCache().getCustomTemplates().get(cacheIdentifier).getTtl(), defaultTimeToLive);
|
||||||
|
Integer maxEntries = Objects.requireNonNullElse(
|
||||||
|
fineractProperties.getCache().getCustomTemplates().get(cacheIdentifier).getMaximumEntries(), defaultMaxEntries);
|
||||||
|
configurationTemplate = generateCacheConfiguration(maxEntries, timeToLiveExpiration);
|
||||||
|
}
|
||||||
|
return configurationTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static javax.cache.configuration.Configuration<Object, Object> generateCacheConfiguration(Integer defaultMaxEntries,
|
||||||
|
Duration defaultTimeToLive) {
|
||||||
|
return Eh107Configuration.fromEhcacheCacheConfiguration(CacheConfigurationBuilder
|
||||||
|
.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(defaultMaxEntries))
|
||||||
|
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(defaultTimeToLive)).build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,6 +284,13 @@ fineract.sql-validation.profiles[2].patternRefs[6].name=inject-comment
|
|||||||
fineract.sql-validation.profiles[2].patternRefs[6].order=6
|
fineract.sql-validation.profiles[2].patternRefs[6].order=6
|
||||||
fineract.sql-validation.profiles[2].enabled=true
|
fineract.sql-validation.profiles[2].enabled=true
|
||||||
|
|
||||||
|
#Cache - Default
|
||||||
|
fineract.cache.default-template.ttl=1m
|
||||||
|
fineract.cache.default-template.maximum-entries=1000
|
||||||
|
#Cache - Customization
|
||||||
|
fineract.cache.custom-templates.userTFAccessToken.ttl=2h
|
||||||
|
fineract.cache.custom-templates.userTFAccessToken.maximum-entries=10000
|
||||||
|
|
||||||
# Logging pattern for the console
|
# Logging pattern for the console
|
||||||
logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) [%15.15tenantId] %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
|
logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) [%15.15tenantId] %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
|
||||||
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]
|
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]
|
||||||
|
|||||||
@@ -202,6 +202,10 @@ fineract.sql-validation.profiles[2].patternRefs[7].name=inject-comment
|
|||||||
fineract.sql-validation.profiles[2].patternRefs[7].order=7
|
fineract.sql-validation.profiles[2].patternRefs[7].order=7
|
||||||
fineract.sql-validation.profiles[2].enabled=true
|
fineract.sql-validation.profiles[2].enabled=true
|
||||||
|
|
||||||
|
#Cache - Default
|
||||||
|
fineract.cache.default-template.ttl=1m
|
||||||
|
fineract.cache.default-template.maximum-entries=1000
|
||||||
|
|
||||||
management.health.jms.enabled=false
|
management.health.jms.enabled=false
|
||||||
|
|
||||||
# FINERACT 1296
|
# FINERACT 1296
|
||||||
|
|||||||
Reference in New Issue
Block a user