Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

messageQueue:
  provider: rabbitmq
  uri: amqps://user:pass@localhost:5671/%2f
  exchangeName: testExchange
  tls:
    enabled: true
    p12KeyPath: C:/certs/rmq.p12
    p12KeyPassphrase: rmqpass
  producer:
    minIdleChannels: 2
    maxIdleChannels: 4
    maxOpenChannels: 6
    sendMessageTimeout: 10000
    threads: 10
    retry:
      retries: 10
      delay: 10000
  consumer:
    directConsumer:
      maxMessages: 4
      mmaxMessageRequeues: 6
    broadcastConsumer:
      maxMessages: 3
      maxMessageRequeues: 6

Circuit Breaker

Overview

The idea behind a circuit breaker is to wrap a protected function call in a circuit breaker object, which monitors for failures. Once the failures reach a certain threshold, the circuit is open, and further calls to the circuit return an error right away instead of executing the protected function. Some parameters then control when the circuit will close again and test whether the protected function can be executed without errors. A more in-depth explanation on the general concept can be found here

This core library provides a wrapper for the registry used in the Circuit Breaker pattern implementation offered by resilience4j. The main purpose of the wrapper is to simplify the configuration of a circuit breaker by exposing only a limited number of configuration parameters, and setting default values for the rest. These parameters values were chosen thinking of a use case where the circuit breaker prevents constant requests to an external API that has returned a 429 error, although it can be used in other scenarios. Of all the parameters found in the documentation linked above, the following are the ones exposed in the builder of the CircuitBreakerRegistryWrapper class, and thus are open to configuration:

The defaults listed in the table are those of the builder, which might differ from those of the library.

ParameterTypeDefault
failureRateThresholdfloat50
slowCallDurationThresholdDuration1 hour
slowCallRateDurationThresholdfloat100
slidingWindowSizeint2
waitDurationInOpenStateDuration60 seconds
recordExceptionsList<Class<? extends Throwable>>empty
ignoreExceptionsList<Class<? extends Throwable>>empty

As for the other configuration parameters, the following values are used:

ParameterTypeValue
permittedNumberOfCallsInHalfOpenStateint1
maxWaitDurationInHalfOpenStateDuration0
slidingWindowTypeSlidingWindowTypeCOUNT_BASED
automaticTransitionFromOpenToHalfOpenEnabledbooleantrue
minimumNumberOfCallsintSame as slidingWindowSize
recordFailurePredicatethrowable -> booleanBy default all exceptions are recorded as failures.
ignoreExceptionPredicatethrowable -> booleanBy default no exception is ignored.

Examples

Creating a default CircuitBreakerRegistryWrapper, using it to create a circuit breaker, and then wrapping a function:

import com.pureinsights.pdp.core.circuitbreaker.CircuitBreakerRegistryWrapper;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;

public class SomeClass {

  // The protected function
  public int doubleNumber(int param) {
    return param * 2;
  }


  // Here's where the circuit breaker is used
  public void callWithCircuitBreaker() {
    // Build the wrapper
    var circuitBreakerWrapper = CircuitBreakerRegistryWrapper.builder().build();
    // Get a circuit breaker instance (the name provided must be unique for each wrapper)
    var cb = circuitBreakerWrapper.getCircuitBreaker("test");
    // Use the instance to decorate the function
    var decorated = CircuitBreaker.decorateFunction(circuitBreaker, this::execute);
    // Call the function
    try {
      var result = decorated.apply(5);
      // The apply method will return an exception if the circuit is open
    } catch (CallNotPermittedException callNotPermittedException) {
      log.error("call not permitted");
    }
  }
}

Creating a CircuitBreakerRegistryWrapper with all custom parameters:

import com.pureinsights.pdp.core.circuitbreaker.CircuitBreakerRegistryWrapper;

public class SomeClass {

  public void foo() {
    ArrayList<Class<? extends Throwable>> customRecordExceptions = new ArrayList<>(
            Arrays.asList(IllegalArgumentException.class, TimeoutException.class));
    ArrayList<Class<? extends Throwable>> customIgnoreExceptions = new ArrayList<>(
            List.of(NullPointerException.class));

    var circuitBreakerWrapper = CircuitBreakerRegistryWrapper.builder()
            .failureRateThreshold(60)
            .slidingWindowSize(10)
            .slowCallDurationThreshold(Duration.ofMillis(120000))
            .slowCallRateThreshold(80)
            .waitDurationInOpenState(Duration.ofMillis(10000))
            .ignoreExceptions(customIgnoreExceptions)
            .recordExceptions(customRecordExceptions)
            .build();
  }
}

Encryption

PDP provides a utilities class called CryptoUtils that allows the user to encrypt and decrypt any given String.

import com.pureinsights.pdp.core.crypto.CryptoUtils;

public class EncrytedEntityEncryptedEntity {
  
  String content;
  
  public EncrytedEntity(String content) {
    this.content = CryptoUtils.encrypt(content);
  }
  
  public String plainContent() {
    return CryptoUtils.decrypt(content);
  }
}

...