...
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.
Parameter | Type | Default |
---|---|---|
failureRateThreshold | float | 50 |
slowCallDurationThreshold | Duration | 1 hour |
slowCallRateDurationThreshold | float | 100 |
slidingWindowSize | int | 2 |
waitDurationInOpenState | Duration | 60 seconds |
recordExceptions | List<Class<? extends Throwable>> | empty |
ignoreExceptions | List<Class<? extends Throwable>> | empty |
As for the other configuration parameters, the following values are used:
Parameter | Type | Value |
---|---|---|
permittedNumberOfCallsInHalfOpenState | int | 1 |
maxWaitDurationInHalfOpenState | Duration | 0 |
slidingWindowType | SlidingWindowType | COUNT_BASED |
automaticTransitionFromOpenToHalfOpenEnabled | boolean | true |
minimumNumberOfCalls | int | Same as slidingWindowSize |
recordFailurePredicate | throwable -> boolean | By default all exceptions are recorded as failures. |
ignoreExceptionPredicate | throwable -> boolean | By 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);
}
}
...