Skip to content

SDA Commons Server Circuit Breaker

javadoc

This module provides the CircuitBreakerBundle, a Dropwizard bundle that is used to inject circuit breakers into service calls.

A circuit breaker is a pattern to make synchronous calls in a distributed system more resilient. This is especially relevant, if a called service hangs without a response, as such failures would cascade up into other services and influence the overall stability of the system. This module doesn't provide an own implementation, but uses the circuit breaker from resilience4j. The bundle also provides prometheus metrics that can be exported in combination with sda-commons-server-prometheus.

Usage

To create a circuit breaker, register the circuit breaker bundle in the application:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private final CircuitBreakerBundle<AppConfiguration> circuitBreakerBundle = CircuitBreakerBundle
      .builder()
      .withDefaultConfig()
      .build();

@Override
public void initialize(Bootstrap<AppConfiguration> bootstrap) {
   bootstrap.addBundle(circuitBreakerBundle);

   ...
}

As the configuration depends on the environment and the load on the service, a different configuration might be required. A custom configuration can be specified globally at the bundle:

1
2
3
4
private final CircuitBreakerBundle<AppConfiguration> circuitBreakerBundle = CircuitBreakerBundle
      .builder()
      .<AppConfiguration>withCustomConfig(new CircuitBreakerConfiguration().setFailureRateThreshold(50.0f))
      .build();

It's also possible to load the configuration from the Dropwizard configuration:

1
2
3
4
private final CircuitBreakerBundle<AppConfiguration> circuitBreakerBundle = CircuitBreakerBundle
      .builder()
      .withConfigProvider(AppConfiguration::getCircuitBreaker)
      .build();

Creating a Circuit Breaker

New circuit breakers can be created from the bundle using a builder pattern:

1
2
3
4
CircuitBreaker circuitBreaker = circuitBreakerBundle
      .createCircuitBreaker("nameInMetrics")
      .withDefaultConfig()
      .build();

In case the global bundle configuration isn't sufficient for the specific instance, a custom configuration can be provided (or loaded from the Dropwizard config using withConfigProvider):

1
2
3
4
5
CircuitBreaker circuitBreaker = circuitBreakerBundle
      .createCircuitBreaker("nameInMetrics")
      .withCustomConfig(new CircuitBreakerConfiguration()
            .setFailureRateThreshold(75.0f))
      .build();

Method calls can be wrapped using the circuit breaker:

1
circuitBreaker.executeSupplier(() -> target.doAction());

See the resilience4j documentation for a full usage guide.

Wrapping with Proxies

In case you would like to wrap all calls to an object with a circuit breaker, the module provides a simple way to achieve this. For example, a Jersey client can be wrapped with a proxy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
serviceClient = circuitBreakerBundle
      .createCircuitBreaker("ServiceClient")
      .withDefaultConfig())
      .wrap(jerseyClientBundle
          .getClientFactory()
          .platformClient()
          .enableAuthenticationPassThrough()
          .enableConsumerToken()
          .api(ServiceClient.class)
          .atTarget(configuration.getUrl()));

serviceClient.doAction();