Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MAJOR] Update to R4j 1.1.0, and implement Retries #7

Merged
merged 4 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be moved to an ### Added section?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, done


### 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