Skip to content

Commit

Permalink
[MAJOR] Update to R4j 1.1.0, and implement Retries (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
breischl authored and eocantu committed Oct 28, 2019
1 parent 50299d0 commit fd26396
Show file tree
Hide file tree
Showing 15 changed files with 715 additions and 85 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ overlays
*.ipr
*.iml
*.iws
.idea
.idea
*.versionsBackup
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).

## [Unreleased]
### Changed
- nothing yet
### Added
- Added support for R4j `Retry`

### Changed
- Updated to R4j 1.1.0. This is a major version bump that has a lot of breaking changes that will be user-visible. See R4j documentation for details.

##[0.0.1] - 2019-03-11
###Initial Version
Expand Down
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ dropwizard-resilience4j-bundle [![Build Status][build-icon]][build-link]


Lightweight integration of Resilience4J into Dropwizard configuration and metrics. Does not provide any other services - actually _using_
all the Resilience4j stuff is up to you.

Currently this only supports Circuit Breakers, but supporting [more R4j features is welcome](http://resilience4j.github.io/resilience4j/#_usage_guide).
all the Resilience4j stuff is up to you. The [R4J documentation](https://resilience4j.readme.io/docs) is pretty good.

Currently this only supports Circuit Breakers and Retries, but supporting [more R4j features is welcome](http://resilience4j.github.io/resilience4j/#_usage_guide).

User Guide
==============================
Expand All @@ -29,10 +28,21 @@ resilience4j:
circuitBreakers:
- name: myFancyCircuitBreaker
waitDurationInOpenState: 30s
ringBufferSizeInClosedState: 30
failureRateThreshold: 10
## Add as many as you want
## All parameters are optional except `name`, defaults are documented in CircuitBreakerConfiguration.java
##- name: anotherCircuitBreaker
retryConfigurations:
- name: exponentialRandomizedBackoffRetry
maxAttempts: 4
intervalFunction:
type: exponentialRandomBackoff
initialInterval: 10ms
multiplier: 2.5
randomizationFactor: 0.5
## Add as many as you want
## most parameters are optional, but `intervalFunction` is required. Several are available, see `IntervalFunctionFactory` for full list,
## but currently: constant, randomized, exponentialBackoff, exponentialRandomBackoff
```

Add to your application's Config class:
Expand All @@ -41,21 +51,28 @@ Add to your application's Config class:
private Resilience4jConfiguration resilience4j;
```

The circuit breakers are automatically wired into Dropwizard Metrics, and also [into HK2 using the name from the YAML](src/main/java/com/homeaway/dropwizard/bundle/resilience4j/Resilience4jBundle.java#L93).
Configured R4J objects are automatically wired into Dropwizard Metrics, and also [into HK2 using the name from the YAML](src/main/java/com/homeaway/dropwizard/bundle/resilience4j/Resilience4jBundle.java#L93).
You can also retrieve them from the configuration class...

```java
val breaker = myAppConfig.getResilience4j().getCircuitBreakerRegistry().circuitBreaker("myFancyCircuitBreaker");
val retry = myAppConfig.getResilience4j().getRetryRegistry().retry("myFancyRetry");
```

If you want to configure the CircuitBreakers in code before they are created, you can pass a handler into the bundle when it's constructed.
If you want to configure the objects in code before they are created, you can pass a handler into the bundle when it's constructed.
```java
@Override
public void initialize(Bootstrap<RatesEngineConfiguration> bootstrap) {
bootstrap.addBundle(new Resilience4jBundle<>(RatesEngineConfiguration::getResilience4j, (breakerName, breakerBuilder) -> {
//breakerName is what was configured in YAML
//breakerBuilder can be modified as desired
breakerBuilder.ignoreExceptions(IOException.class);
}));
bootstrap.addBundle(new Resilience4jBundle<>(TestConfiguration::getResilience4j,
(breakerName, breakerBuilder) -> {
//breakerName is what was configured in YAML
//breakerBuilder can be modified as desired
breakerBuilder.ignoreExceptions(IOException.class);
},
(retryName, retryBuilder) -> {
//retryName is what was configured in YAML
//retryBuilder can be modified as desired
retryBuilder.retryOnResult(myRetryPredicate);
}));
}
```
24 changes: 21 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.expediagroup.dropwizard.bundle</groupId>
<artifactId>dropwizard-resilience4j-bundle</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>dropwizard-resilience4j-bundle</name>
Expand Down Expand Up @@ -45,9 +45,10 @@
<hk2-api.version>2.5.0-b32</hk2-api.version>
<junit.version>4.12</junit.version>
<rs-api.version>2.0.1</rs-api.version>
<resilience4j.version>0.13.1</resilience4j.version>
<resilience4j.version>1.1.0</resilience4j.version>
<slf4j.version>1.7.25</slf4j.version>
<validation-api.version>1.1.0.Final</validation-api.version>
<vavr.version>0.9.2</vavr.version>
<vavr.version>0.10.0</vavr.version>

</properties>

Expand All @@ -64,6 +65,10 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
Expand All @@ -72,6 +77,10 @@
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-jersey</artifactId>
Expand All @@ -94,6 +103,11 @@
<artifactId>resilience4j-metrics</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-retry</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
Expand All @@ -109,6 +123,10 @@
<artifactId>hk2-api</artifactId>
<version>${hk2-api.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>

<!-- Test scoped dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import javax.annotation.Nonnull;

import org.glassfish.hk2.utilities.binding.AbstractBinder;

import com.homeaway.dropwizard.bundle.resilience4j.configuration.CircuitBreakerConfiguration;
import com.homeaway.dropwizard.bundle.resilience4j.configuration.Resilience4jConfiguration;
import com.homeaway.dropwizard.bundle.resilience4j.configuration.retry.RetryConfiguration;

import io.dropwizard.ConfiguredBundle;
import io.dropwizard.setup.Bootstrap;
Expand All @@ -32,33 +33,42 @@
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.internal.InMemoryCircuitBreakerRegistry;
import io.github.resilience4j.core.lang.NonNull;
import io.github.resilience4j.metrics.CircuitBreakerMetrics;
import io.github.resilience4j.metrics.RetryMetrics;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
import io.github.resilience4j.retry.internal.InMemoryRetryRegistry;

public class Resilience4jBundle<T> implements ConfiguredBundle<T> {

private final Function<T, Resilience4jConfiguration> resiliencyConfiguratorFunction;

private final BiConsumer<String, CircuitBreakerConfig.Builder> circuitBreakerConfigurator;

private static final BiConsumer<String, CircuitBreakerConfig.Builder> NOOP_CONFIGURATOR = (a, b) -> {
};
private final BiConsumer<String, RetryConfig.Builder> retryConfigurator;

/**
* Create a new bundle
*/
public Resilience4jBundle(@Nonnull Function<T, Resilience4jConfiguration> resilienceConfiguratorFunction) {
this(resilienceConfiguratorFunction, NOOP_CONFIGURATOR);
public Resilience4jBundle(@NonNull Function<T, Resilience4jConfiguration> resilienceConfiguratorFunction) {
this(resilienceConfiguratorFunction,
noOpConfigurator(),
noOpConfigurator());
}

/**
* Create a new bundle, with a function for modifying CircuitBreaker configurations
*
* @param circuitBreakerConfigurator A function that will be passed the name and builder for each circuit breaker before it is created
*/
public Resilience4jBundle(@Nonnull Function<T, Resilience4jConfiguration> resilienceConfiguratorFunction,
@Nonnull BiConsumer<String, CircuitBreakerConfig.Builder> circuitBreakerConfigurator) {
public Resilience4jBundle(@NonNull Function<T, Resilience4jConfiguration> resilienceConfiguratorFunction,
@NonNull BiConsumer<String, CircuitBreakerConfig.Builder> circuitBreakerConfigurator,
@NonNull BiConsumer<String, RetryConfig.Builder> retryConfigurator) {
this.resiliencyConfiguratorFunction = resilienceConfiguratorFunction;
this.circuitBreakerConfigurator = circuitBreakerConfigurator;
this.retryConfigurator = retryConfigurator;
}

@Override
Expand Down Expand Up @@ -100,5 +110,42 @@ protected void configure() {
}
});
}

final List<RetryConfiguration> retryConfigs = config.getRetryConfigurations();
if (retryConfigs != null & !retryConfigs.isEmpty()) {
final InMemoryRetryRegistry retryRegistry = new InMemoryRetryRegistry();
for (final RetryConfiguration cfg : retryConfigs) {
final RetryConfig.Builder r4jConfigBuilder = cfg.toResilience4jConfigBuilder();
retryConfigurator.accept(cfg.getName(), r4jConfigBuilder);
retryRegistry.retry(cfg.getName(), r4jConfigBuilder.build());
}

config.setRetryRegistry(retryRegistry);

//Register retry metrics with Dropwizard metrics
environment.metrics().registerAll(RetryMetrics.ofRetryRegistry(retryRegistry));

//Register retryers with Jersey for injection, if anybody wants to use it
environment.jersey().register(new AbstractBinder() {

@Override
protected void configure() {
//Bind the registry
bind(retryRegistry).to(RetryRegistry.class);

//Bind each of the retryers
for (final Retry retryer : retryRegistry.getAllRetries()) {
bind(retryer).to(Retry.class).named(retryer.getName());
}
}
});
}
}

private static final BiConsumer<Object, Object> NOOP_CONFIGURATOR = (a, b) -> {
};

private static <T, U> BiConsumer<T, U> noOpConfigurator() {
return (BiConsumer<T, U>) NOOP_CONFIGURATOR;
}
}
Loading

0 comments on commit fd26396

Please sign in to comment.