Spring Cache-仅当API响应成功时才清除缓存



我正在使用Spring Cache@CacheEvict&@Cacheable

目前,我每小时运行一个调度程序来清除缓存,下次调用fetchUser((时,它将从外部APi获取数据并添加到缓存中。

@Scheduled(cron = "0 0 * * * *}")
@CacheEvict(value = "some-unique-value", allEntries = true)
public void clearUserCache() {
log.info("Cache cleared");
}
@Cacheable(value = "some-unique-value", unless = "#result.isFailure()")
@Override
public Result<UserResponse> fetchUser() {
try {
UserResponse userResponse = api.fetchUserDetail();
return Result.success(userResponse);
} catch (Exception e) {
return Result.failure(INTERNAL_SERVER_ERROR);
}
}

现在我们需要的是只有当用户API调用成功时才清除缓存。有办法做到这一点吗。

现在按计划清除缓存,并假设外部API调用失败。主API将返回错误响应。在这种情况下,我应该能够使用现有的缓存本身。

如果我正确地得到了它,为什么不在检查API调用在该方法的父级是否正确后将其作为正常方法调用?

用你的代码,一些类似的东西

// we just leave scheduled here as you need it.
@Scheduled(cron = "0 0 * * * *}")
@CacheEvict(value = "some-unique-value", allEntries = true)
public void clearUserCache() {
log.info("Cache cleared");
}
@Cacheable(value = "some-unique-value", unless = "#result.isFailure()")
@Override
public Result<UserResponse> fetchUser() {
try {
UserResponse userResponse = api.fetchUserDetail();
return Result.success(userResponse);
} catch (Exception e) {
return Result.failure(INTERNAL_SERVER_ERROR);
}
}
public void parentMethod() {
Result<UserResponse> userResult = this.fetchUser();
if(userResult.isFailure()) {
this.clearUserCache();
}
}

这样,如果抛出任何Exception,它将返回failure状态,您可以对其进行检查。因此,缓存将每小时清除一次,或者在不工作时清除一次

所以下一次,由于它失败了,而且没有缓存,它会再试一次。

我没有找到任何直接的实现,但通过一个解决方案,我能够做到。

用例

  • 只有在触发使用用户API的下一个服务调用时,才应更新用户API响应。调度程序不应更新它。由于我们需要将来自外部系统的头信息传递给用户API
  • 只有当用户API响应成功时,才必须清除缓存

步骤:

  • 在调度程序中添加了一个变量,并在调度时间时将其设置为ON,在更新缓存时将其设为OFF
  • 这个标志在UserService类中用于检查调度程序是否被触发
  • 如果没有,请使用缓存。如果是true,则触发用户API调用。如果成功,请检查响应。触发CacheEvict方法并更新Cache

示例代码:

调度配置

private boolean updateUserCache;
@Scheduled(cron = "${0 0 * * * *}") // runs every Hr
public void userScheduler() {
updateUserCache = true;
log.info("Scheduler triggered for User");
}
@CacheEvict(value = "USER_CACHE", allEntries = true)
public void clearUserCache() {
updateUserCache = false;
log.info("User cache cleared");
}
public boolean isUserCacheUpdateRequired() {
return updateUserCache;
}

用户服务

UserResponse userResponse = null;
if (schedulerConfig.isUserCacheUpdateRequired()) {
userResponse = userCache.fetchUserDetail(); 
if (userResponse != null) {
// clear's cache and userResponse is stored in cache automatically when getUserDetail is called below
schedulerConfig.clearUserCache(); 
}
}
return userCache.getUserDetail(userResponse);

用户缓存

@Cacheable(value = "USER_CACHE", key = "#root.targetClass", unless = "#result.isFailure()")
public Result<User> getUserDetail(UserResponse userResponse) {
try {
if (userResponse == null) { // handle first time trigger when cache is not available
userResponse = fetchUserDetail(); // actual API call 
}
return Result.success(mapToUser(userResponse));
} catch (Exception e) {
return Result.failure("Error Response");
}
}

注意:

  • Result是一个自定义的Wrapper,假设它是一个具有成功或失败属性的对象
  • 我不得不将@Cacheable部分添加为单独的Bean,因为缓存只适用于代理对象。如果我将getUserDetail保留在UserService内部并直接调用,则由于代理和缓存逻辑不工作,它不会被拦截,每次都会触发API调用
  • 最重要的是:这不是最好的解决方案,还有改进的余地

最新更新