@Cacheable 이용시 redis 를 활용해서 캐싱할수 있다.
관련된 코드는 이전 포스팅 참고해도 되고, spring cache redis 검색해서 나오는 다른 블로그를 참고 하자.
하지만 의존하는 모든 외부 서비스는 장애에 대한 대응을 해야 한다.
예를들어 레디스가 동작하지 않는 동안에는 캐시가 아닌 DB 에서 조회 하도록 fallback 기능이 있어야 한다.
AWS Elasticache 라면 믿고 맡겨도 되겠지 하겠지만 어떤 서비스라도 SLA 100% 를 믿지 않는게 좋다.
장애 뿐만 아니라 일시적인 업데이트 등 순단에 대해서도 우리 서비스의 안정성을 높일수 있다.
이때 spring-retry 의 @Retryable 과 @Recover 를 사용하면 된다.
@Retryable 은 예외 발생시 재시도를 하고, @Recover는 재시도 실패시에 동작하는 어노테이션 이다.
implementation ("org.springframework.retry:spring-retry")
@Slf4j
@Service
@RequiredArgsConstructor
public class StoreBeaconService {
private final StoreBeaconRepository storeBeaconRepository;
private final DtoMapper mapper;
@CacheEvict(cacheNames = "allBeacons", key = "'allBeacons:'+#storeId")
public void addBeacon(Long storeId, String beaconNumber) {
storeBeaconRepository.save(new StoreBeacon(new Beacon(beaconNumber), storeId));
}
@Retryable(maxAttempts = 1)
@Cacheable(cacheNames = "allBeacons", key = "'allBeacons:'+#storeId")
public List<StoreBeaconSignalHistoryDto> allBeacons(Long storeId) {
return find(storeId);
}
@Recover
public List<StoreBeaconSignalHistoryDto> allBeacons(Exception e, Long storeId) {
log.error(e.getMessage());
return find(storeId);
}
private List<StoreBeaconSignalHistoryDto> find(Long storeId) {
return storeBeacon(storeId).stream()
.map(x -> mapper.mapToStoreBeaconSignalHistory(1L,
new StoreBeaconSignalHistory(2L, x, SignalStatus.IN_SIGNAL,
Collections.emptyList())))
.collect(Collectors.toList());
}
private List<StoreBeacon> storeBeacon(Long storeId) {
return storeBeaconRepository.findByStoreId(storeId);
}
}
circuit breaker pattern
의 Halp Open
개념이 없다.circuit breaker pattern
구현이 필요하다면 spring-retry 보다는 spring-cloud-starter-circuitbreaker-spring-retry
를 알아보는게 좋다.circuit breaker pattern?
spring-cloud-circuit-breaker
spring-cloud-circuit-breaker 예제