forked from ReactiveX/RxJava
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue ReactiveX#72: Added retry metrics to resilience4j-metrics
- Loading branch information
Showing
13 changed files
with
345 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
dependencies { | ||
compile (libraries.metrics) | ||
compileOnly project(':resilience4j-circuitbreaker') | ||
compileOnly project(':resilience4j-retry') | ||
compileOnly project(':resilience4j-ratelimiter') | ||
testCompile project(':resilience4j-test') | ||
testCompile project(':resilience4j-circuitbreaker') | ||
testCompile project(':resilience4j-ratelimiter') | ||
testCompile project(':resilience4j-retry') | ||
testCompile project(':resilience4j-test') | ||
testCompile project(':resilience4j-circuitbreaker') | ||
} |
82 changes: 82 additions & 0 deletions
82
resilience4j-metrics/src/main/java/io/github/resilience4j/metrics/RetryMetrics.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package io.github.resilience4j.metrics; | ||
|
||
import com.codahale.metrics.*; | ||
import io.github.resilience4j.retry.Retry; | ||
import io.github.resilience4j.retry.RetryRegistry; | ||
import javaslang.collection.Array; | ||
|
||
import java.util.Map; | ||
|
||
import static com.codahale.metrics.MetricRegistry.name; | ||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* An adapter which exports {@link Retry.Metrics} as Dropwizard Metrics Gauges. | ||
*/ | ||
public class RetryMetrics implements MetricSet { | ||
|
||
private final MetricRegistry metricRegistry = new MetricRegistry(); | ||
private static final String DEFAULT_PREFIX = "resilience4j.retry"; | ||
|
||
private RetryMetrics(Iterable<Retry> retries){ | ||
this(DEFAULT_PREFIX, retries); | ||
} | ||
|
||
private RetryMetrics(String prefix, Iterable<Retry> retries){ | ||
requireNonNull(prefix); | ||
requireNonNull(retries); | ||
retries.forEach(retry -> { | ||
String name = retry.getName(); | ||
Retry.Metrics metrics = retry.getMetrics(); | ||
|
||
metricRegistry.register(name(prefix, name, "retry_max_ratio"), | ||
new RetryRatio(metrics.getNumAttempts(), metrics.getMaxAttempts())); | ||
|
||
}); | ||
} | ||
|
||
public static RetryMetrics ofRateLimiterRegistry(String prefix, RetryRegistry retryRegistry) { | ||
return new RetryMetrics(prefix, retryRegistry.getAllRetries()); | ||
} | ||
|
||
public static RetryMetrics ofRateLimiterRegistry(RetryRegistry retryRegistry) { | ||
return new RetryMetrics(retryRegistry.getAllRetries()); | ||
} | ||
|
||
public static RetryMetrics ofIterable(String prefix, Iterable<Retry> retries) { | ||
return new RetryMetrics(prefix, retries); | ||
} | ||
|
||
public static RetryMetrics ofIterable(Iterable<Retry> retries) { | ||
return new RetryMetrics(retries); | ||
} | ||
|
||
public static RetryMetrics ofRateLimiter(Retry retry) { | ||
return new RetryMetrics(Array.of(retry)); | ||
} | ||
|
||
@Override | ||
public Map<String, Metric> getMetrics() { | ||
return metricRegistry.getMetrics(); | ||
} | ||
|
||
/** | ||
* Implements a {@link RatioGauge} that represents the ratio between attempts made, and the maximum allowed retry attempts. | ||
*/ | ||
private final class RetryRatio extends RatioGauge { | ||
|
||
private double numAttempts; | ||
|
||
private double maxAttempts; | ||
|
||
public RetryRatio(int numAttempts, int maxAttempts) { | ||
this.numAttempts = (double) numAttempts; | ||
this.maxAttempts = (double) maxAttempts; | ||
} | ||
|
||
@Override | ||
protected Ratio getRatio() { | ||
return Ratio.of(numAttempts, maxAttempts); | ||
} | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
resilience4j-metrics/src/test/java/io/github/resilience4j/metrics/RetryMetricsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package io.github.resilience4j.metrics; | ||
|
||
import com.codahale.metrics.MetricRegistry; | ||
import io.github.resilience4j.circuitbreaker.CircuitBreaker; | ||
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; | ||
import io.github.resilience4j.retry.Retry; | ||
import io.github.resilience4j.retry.RetryRegistry; | ||
import io.github.resilience4j.test.HelloWorldService; | ||
import javaslang.control.Try; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.mockito.BDDMockito; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.times; | ||
|
||
public class RetryMetricsTest { | ||
|
||
private MetricRegistry metricRegistry; | ||
private HelloWorldService helloWorldService; | ||
|
||
@Before | ||
public void setUp(){ | ||
metricRegistry = new MetricRegistry(); | ||
helloWorldService = mock(HelloWorldService.class); | ||
} | ||
|
||
@Test | ||
public void shouldRegisterMetrics() throws Throwable { | ||
//Given | ||
RetryRegistry retryRegistry = RetryRegistry.ofDefaults(); | ||
Retry retry = retryRegistry.retry("testName"); | ||
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); | ||
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); | ||
metricRegistry.registerAll(RetryMetrics.ofRateLimiterRegistry(retryRegistry)); | ||
|
||
// Given the HelloWorldService returns Hello world | ||
BDDMockito.given(helloWorldService.returnHelloWorld()).willReturn("Hello world"); | ||
|
||
// Setup circuitbreaker with retry | ||
Try.CheckedSupplier<String> decoratedSupplier = CircuitBreaker | ||
.decorateCheckedSupplier(circuitBreaker, helloWorldService::returnHelloWorld); | ||
decoratedSupplier = Retry | ||
.decorateCheckedSupplier(retry, decoratedSupplier); | ||
|
||
|
||
//When | ||
String value = Try.of(decoratedSupplier) | ||
.recover(throwable -> "Hello from Recovery").get(); | ||
|
||
//Then | ||
assertThat(value).isEqualTo("Hello world"); | ||
// Then the helloWorldService should be invoked 1 time | ||
BDDMockito.then(helloWorldService).should(times(1)).returnHelloWorld(); | ||
assertThat(metricRegistry.getMetrics()).hasSize(1); | ||
assertThat(metricRegistry.getGauges().get("resilience4j.retry.testName.retry_max_ratio").getValue()).isEqualTo(0.0); | ||
} | ||
|
||
@Test | ||
public void shouldUseCustomPrefix() throws Throwable { | ||
//Given | ||
RetryRegistry retryRegistry = RetryRegistry.ofDefaults(); | ||
Retry retry = retryRegistry.retry("testName"); | ||
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); | ||
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName"); | ||
metricRegistry.registerAll(RetryMetrics.ofRateLimiterRegistry("testPrefix",retryRegistry)); | ||
|
||
// Given the HelloWorldService returns Hello world | ||
BDDMockito.given(helloWorldService.returnHelloWorld()).willReturn("Hello world"); | ||
|
||
// Setup circuitbreaker with retry | ||
Try.CheckedSupplier<String> decoratedSupplier = CircuitBreaker | ||
.decorateCheckedSupplier(circuitBreaker, helloWorldService::returnHelloWorld); | ||
decoratedSupplier = Retry | ||
.decorateCheckedSupplier(retry, decoratedSupplier); | ||
|
||
//When | ||
String value = Try.of(decoratedSupplier) | ||
.recover(throwable -> "Hello from Recovery").get(); | ||
|
||
//Then | ||
assertThat(value).isEqualTo("Hello world"); | ||
// Then the helloWorldService should be invoked 1 time | ||
BDDMockito.then(helloWorldService).should(times(1)).returnHelloWorld(); | ||
assertThat(metricRegistry.getMetrics()).hasSize(1); | ||
assertThat(metricRegistry.getGauges().get("testPrefix.testName.retry_max_ratio").getValue()).isEqualTo(0.0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.