Microservices with Java — Part 2

Fault tolerance and Configuration Server

Fault Tolerance

Fault tolerance is the property that enables a system to continue operating properly in the event of the failure of some of its components [1].

  • how many of those should fail;
  • timeout duration to be considered;
  • how long after a circuit trip to try again.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> globalCustomConfiguration() {
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(4))
.build();
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slidingWindowSize(2)
.build();
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.timeLimiterConfig(timeLimiterConfig)
.circuitBreakerConfig(circuitBreakerConfig)
.build());
}
@Service  @AllArgsConstructor
public class IntegrationService {

private final UserFeignClient userFeignClient;
private final ProductFeignClient productFeignClient;
private final CircuitBreakerFactory circuitBreakerFactory;
private final String USER_SERVICE_NAME = "USER-INFORMATION-SERVICE";
private final String PRODUCT_SERVICE_NAME = "PRODUCT-CATALOG-SERVICE";

public UserInfo getRemoteUserInfo(Long userId) {
// wrap in circuit breaker for fault tolerance
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
var user = circuitBreaker.run(() -> userFeignClient.findById(userId), throwable -> this.findUserByIdFallBack(userId));
return user;
}

public List<Item> getRemoteProductItemsInfo(List<Item> items) {
items.forEach(item -> {
// wrap in circuit breaker for fault tolerance
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
var product = circuitBreaker.run(() -> productFeignClient.findById(item.getProduct().getId()),
throwable -> this.findProductByIdFallBack(item.getProduct().getId()));

item.setProduct(product);
});
return items;
}
// fallback: returns default object
private UserInfo findUserByIdFallBack(Long id) {
return new UserInfo(id, "name info unavailable", null, null);
}

private ProductOverview findProductByIdFallBack(Long id) {
return new ProductOverview(id, "product name unavailable", null);
}
}
POST request with fallback response

Configuration Server

Another improvement we can make in our system is to use a centralized configuration server.

Config Server project setup
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
spring:
application:
name: CONFIG-SERVER-SERVICE
cloud:
config:
server:
git:
uri: https://github.com/tiagoamp/microservices-series
search-paths: configs
server:
port: 8084
spring:
profiles:
active: default
cloud:
config:
uri: http://localhost:8084/
POST request with microservices using Config Server for configuration properties

Software Craftsman

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store