-
Notifications
You must be signed in to change notification settings - Fork 2.7k
FINERACT-1724: Making global configuration caching transaction bound #3041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,23 +19,22 @@ | |
| package org.apache.fineract.infrastructure.configuration.domain; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import lombok.RequiredArgsConstructor; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.fineract.infrastructure.cache.domain.CacheType; | ||
| import org.apache.fineract.infrastructure.cache.domain.PlatformCache; | ||
| import org.apache.fineract.infrastructure.cache.domain.PlatformCacheRepository; | ||
| import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData; | ||
| import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; | ||
| import org.apache.fineract.useradministration.domain.Permission; | ||
| import org.apache.fineract.useradministration.domain.PermissionRepository; | ||
| import org.apache.fineract.useradministration.exception.PermissionNotFoundException; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.cache.annotation.Cacheable; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Slf4j | ||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class ConfigurationDomainServiceJpa implements ConfigurationDomainService { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... see my comment on global configuration service... pretty much the same here. |
||
|
|
||
| public static final String ENABLE_BUSINESS_DATE = "enable_business_date"; | ||
|
|
@@ -55,15 +54,6 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService | |
| private final PermissionRepository permissionRepository; | ||
| private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; | ||
| private final PlatformCacheRepository cacheTypeRepository; | ||
| private static Map<String, GlobalConfigurationPropertyData> configurations = new HashMap<>(); | ||
|
|
||
| @Autowired | ||
| public ConfigurationDomainServiceJpa(final PermissionRepository permissionRepository, | ||
| final GlobalConfigurationRepositoryWrapper globalConfigurationRepository, final PlatformCacheRepository cacheTypeRepository) { | ||
| this.permissionRepository = permissionRepository; | ||
| this.globalConfigurationRepository = globalConfigurationRepository; | ||
| this.cacheTypeRepository = cacheTypeRepository; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isMakerCheckerEnabledForTask(final String taskPermissionCode) { | ||
|
|
@@ -321,9 +311,7 @@ public Long getDailyTPTLimit() { | |
|
|
||
| @Override | ||
| public void removeGlobalConfigurationPropertyDataFromCache(final String propertyName) { | ||
| String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); | ||
| String key = identifier + "_" + propertyName; | ||
| configurations.remove(key); | ||
| globalConfigurationRepository.removeFromCache(propertyName); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -389,15 +377,8 @@ public Long retrieveRelaxingDaysConfigForPivotDate() { | |
| return property.getValue(); | ||
| } | ||
|
|
||
| @Cacheable(value = "configByName", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#propertyName)") | ||
| public GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) { | ||
| String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); | ||
| String key = identifier + "_" + propertyName; | ||
| if (!configurations.containsKey(key)) { | ||
| GlobalConfigurationProperty configuration = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); | ||
| configurations.put(key, configuration.toData()); | ||
| } | ||
| return configurations.get(key); | ||
| private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) { | ||
| return globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName).toData(); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,8 +18,11 @@ | |
| */ | ||
| package org.apache.fineract.infrastructure.configuration.domain; | ||
|
|
||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyNotFoundException; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.cache.annotation.CacheEvict; | ||
| import org.springframework.cache.annotation.Cacheable; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| /** | ||
|
|
@@ -28,6 +31,7 @@ | |
| * </p> | ||
| */ | ||
| @Service | ||
| @Slf4j | ||
| public class GlobalConfigurationRepositoryWrapper { | ||
|
|
||
| private final GlobalConfigurationRepository repository; | ||
|
|
@@ -37,6 +41,7 @@ public GlobalConfigurationRepositoryWrapper(final GlobalConfigurationRepository | |
| this.repository = repository; | ||
| } | ||
|
|
||
| @Cacheable(value = "configByName", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#propertyName)") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just in general: I would try to eliminate this service all together... as can be seen with this requirement to add caching... this thing is just getting in the way and it's not really dev-ops friendly (as you need a database in the first place to be able to do your configuration... instead of simple files)... just saying it again: I think reloadable configurations are a solved problem in Spring/Boot... my 2 cents here: this service is creating more head-aches than it provides solutions. But maybe a discussion for another day. |
||
| public GlobalConfigurationProperty findOneByNameWithNotFoundDetection(final String propertyName) { | ||
| final GlobalConfigurationProperty property = this.repository.findOneByName(propertyName); | ||
| if (property == null) { | ||
|
|
@@ -61,4 +66,8 @@ public void delete(final GlobalConfigurationProperty globalConfigurationProperty | |
| this.repository.delete(globalConfigurationProperty); | ||
| } | ||
|
|
||
| @CacheEvict(value = "configByName", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#propertyName)") | ||
| public void removeFromCache(String propertyName) { | ||
| log.debug("Cache entry evicted {}", propertyName); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably I missed (a lot of) the conversation around this feature... but is there really a use case where you have to switch cache implementation during runtime? That seems to me such an important architectural decision that I would say it is done way before any instance of Fineract is running, at the least you would decide if EH Cache is enough or if you need it at all (I'd say the answer here is always yes... but not sure if you guys discussed a use case where no cache is desirable).
BTW: multi-node cache... Redis is your friend... 1st class support in Spring Boot and works really great (read: performant).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For multi node cache for defo we should use Redis