Skip to content

Commit

Permalink
Resilient modules merged into one (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
GoodforGod authored Aug 7, 2023
1 parent 6700b37 commit 162016f
Show file tree
Hide file tree
Showing 102 changed files with 710 additions and 827 deletions.
5 changes: 1 addition & 4 deletions micrometer/micrometer-module/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ dependencies {
compileOnly project(':jms')
compileOnly project(':database:database-common')
compileOnly project(':scheduling:scheduling-common')
compileOnly project(':resilient:resilient-circuitbreaker')
compileOnly project(':resilient:resilient-fallback')
compileOnly project(':resilient:resilient-retry')
compileOnly project(':resilient:resilient-timeout')
compileOnly project(':resilient:resilient-kora')
compileOnly project(':cache:cache-common')
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ru.tinkoff.kora.micrometer.module.resilient;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import ru.tinkoff.kora.resilient.circuitbreaker.CircuitBreaker.State;
import ru.tinkoff.kora.resilient.circuitbreaker.telemetry.CircuitBreakerMetrics;
import io.micrometer.core.instrument.binder.BaseUnits;
import ru.tinkoff.kora.resilient.circuitbreaker.CircuitBreaker;
import ru.tinkoff.kora.resilient.circuitbreaker.CircuitBreakerMetrics;

import javax.annotation.Nonnull;
import java.util.Map;
Expand All @@ -12,28 +14,49 @@

public final class MicrometerCircuitBreakerMetrics implements CircuitBreakerMetrics {

private final Map<String, AtomicInteger> metrics = new ConcurrentHashMap<>();
private final Map<String, StateMetrics> metrics = new ConcurrentHashMap<>();
private final MeterRegistry registry;

private record StateMetrics(AtomicInteger stateValue, Gauge state, Counter transitionOpen, Counter transitionHalfOpen) { }

public MicrometerCircuitBreakerMetrics(MeterRegistry registry) {
this.registry = registry;
}

@Override
public void recordState(@Nonnull String name, @Nonnull State newState) {
final AtomicInteger state = metrics.computeIfAbsent(name, k -> {
public void recordState(@Nonnull String name, @Nonnull CircuitBreaker.State newState) {
final StateMetrics stateMetrics = metrics.computeIfAbsent(name, k -> {
final AtomicInteger gaugeState = new AtomicInteger(asIntState(newState));
Gauge.builder("resilient.circuitbreaker.state", gaugeState::get)
final Gauge state = Gauge.builder("resilient.circuitbreaker.state", gaugeState::get)
.tag("name", name)
.description("Circuit Breaker state metrics, where 0 -> CLOSED, 1 -> HALF_OPEN, 2 -> OPEN")
.register(registry);
return gaugeState;

final Counter transOpen = Counter.builder("resilient.circuitbreaker.transition")
.baseUnit(BaseUnits.OPERATIONS)
.tag("name", name)
.tag("state", CircuitBreaker.State.OPEN.name())
.register(registry);

final Counter transHalfOpen = Counter.builder("resilient.circuitbreaker.transition")
.baseUnit(BaseUnits.OPERATIONS)
.tag("name", name)
.tag("state", CircuitBreaker.State.HALF_OPEN.name())
.register(registry);

return new StateMetrics(gaugeState, state, transOpen, transHalfOpen);
});

state.set(asIntState(newState));
stateMetrics.stateValue().set(asIntState(newState));

if(newState == CircuitBreaker.State.OPEN) {
stateMetrics.transitionOpen().increment();
} else if(newState == CircuitBreaker.State.HALF_OPEN) {
stateMetrics.transitionHalfOpen().increment();
}
}

private int asIntState(State state) {
private int asIntState(CircuitBreaker.State state) {
return switch (state) {
case CLOSED -> 0;
case HALF_OPEN -> 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.BaseUnits;
import ru.tinkoff.kora.resilient.fallback.telemetry.FallbackMetrics;
import ru.tinkoff.kora.resilient.fallback.FallbackMetrics;

import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -22,7 +22,7 @@ public MicrometerFallbackMetrics(MeterRegistry registry) {
@Override
public void recordExecute(@Nonnull String name, @Nonnull Throwable throwable) {
var metrics = this.metrics.computeIfAbsent(name, k -> build(name));
metrics.attempts.increment();
metrics.attempts().increment();
}

private Metrics build(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.BaseUnits;
import ru.tinkoff.kora.resilient.retry.telemetry.RetryMetrics;
import ru.tinkoff.kora.resilient.retry.RetryMetrics;

import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -22,13 +22,13 @@ public MicrometerRetryMetrics(MeterRegistry registry) {
@Override
public void recordAttempt(@Nonnull String name, long delayInNanos) {
final Metrics metrics = this.metrics.computeIfAbsent(name, k -> build(name));
metrics.attempts.increment();
metrics.attempts().increment();
}

@Override
public void recordExhaustedAttempts(@Nonnull String name, int totalAttempts) {
var metrics = this.metrics.computeIfAbsent(name, k -> build(name));
metrics.exhausted.increment();
metrics.exhausted().increment();
}

private Metrics build(String name) {
Expand All @@ -37,7 +37,7 @@ private Metrics build(String name) {
.tag("name", name)
.register(registry);

var exhausted = io.micrometer.core.instrument.Counter.builder("resilient.retry.exhausted")
var exhausted = Counter.builder("resilient.retry.exhausted")
.baseUnit(BaseUnits.OPERATIONS)
.tag("name", name)
.register(registry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.BaseUnits;
import ru.tinkoff.kora.resilient.timeout.telemetry.TimeoutMetrics;
import ru.tinkoff.kora.resilient.timeout.TimeoutMetrics;

import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -22,7 +22,7 @@ public MicrometerTimeoutMetrics(MeterRegistry registry) {
@Override
public void recordTimeout(@Nonnull String name, long timeoutInNanos) {
var metrics = this.metrics.computeIfAbsent(name, k -> build(name));
metrics.exhausted.increment();
metrics.exhausted().increment();
}

private Metrics build(String name) {
Expand Down
78 changes: 22 additions & 56 deletions mkdocs/docs/features/resilient.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@
- [Combination](#Combination)
- [Поддерживаемые AOP типы](#supported-types)

## Dependency

**Java**:
```groovy
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-kora"
```

**Kotlin**:
```groovy
ksp "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-kora"
```

### Module

```java
@KoraApp
public interface ApplicationModules extends ResilientModule { }
```


## CircuitBreaker

CircuitBreaker – это прокси, который контролирует поток к запросам к конкретному методу,
Expand All @@ -32,20 +54,6 @@ CircuitBreaker – это прокси, который контролирует

Изначально имеет состояние CLOSED.

#### Dependency

**Java**:
```groovy
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-circuitbreaker"
```

**Kotlin**:
```groovy
ksp "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-circuitbreaker"
```

#### Module

```java
Expand Down Expand Up @@ -146,20 +154,6 @@ Retryable - предоставляет возможность настраива

Позволяет указать когда требуется повторить попытку выполнения метода, настроить параметры повторения, в случае если методом была брошена ошибка (Exception) соответствующая заданным требованиям повторения (*RetrierFailurePredicate*).

#### Dependency

**Java**:
```groovy
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-retry"
```

**Kotlin**:
```groovy
ksp "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-retry"
```

#### Module

```java
Expand Down Expand Up @@ -244,20 +238,6 @@ Timeout - предоставляет возможность задания па

Позволяет задать предельное время выполнения операции / метода.

#### Dependency

**Java**:
```groovy
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-timeout"
```

**Kotlin**:
```groovy
ksp "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-timeout"
```

#### Module

```java
Expand Down Expand Up @@ -311,20 +291,6 @@ resilient {
Fallback - предоставляет возможность указания метода который будет вызван в случае
если исключение брошенное проаннотированным методом будет удовлетворено (*FallbackFailurePredicate*).

#### Dependency

**Java**:
```groovy
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-fallback"
```

**Kotlin**:
```groovy
ksp "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:resilient-fallback"
```

#### Module

```java
Expand Down
5 changes: 1 addition & 4 deletions resilient/resilient-annotation-processor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ dependencies {
testImplementation project(":config:config-annotation-processor")
testImplementation project(":config:config-hocon")
testImplementation project(":internal:test-logging")
testImplementation project(":resilient:resilient-circuitbreaker")
testImplementation project(":resilient:resilient-retry")
testImplementation project(":resilient:resilient-timeout")
testImplementation project(":resilient:resilient-fallback")
testImplementation project(":resilient:resilient-kora")
testImplementation "com.google.testing.compile:compile-testing:0.19"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ru.tinkoff.kora.resilient.annotation.processor.aop;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import ru.tinkoff.kora.annotation.processor.common.MethodUtils;
import ru.tinkoff.kora.annotation.processor.common.ProcessingError;
Expand All @@ -9,6 +10,7 @@
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import java.util.List;
Expand Down Expand Up @@ -65,8 +67,6 @@ public ApplyResult apply(ExecutableElement method, String superCall, AspectConte

private CodeBlock buildBodySync(ExecutableElement method, String superCall, String circuitBreakerField) {
final CodeBlock superMethod = buildMethodCall(method, superCall);
final String returnType = method.getReturnType().toString();

final CodeBlock methodCall = MethodUtils.isVoid(method)
? superMethod
: CodeBlock.of("var t = $L", superMethod.toString());
Expand All @@ -75,20 +75,22 @@ private CodeBlock buildBodySync(ExecutableElement method, String superCall, Stri
? CodeBlock.of("return")
: CodeBlock.of("return t", superMethod.toString());

final ClassName cbException = ClassName.get("ru.tinkoff.kora.resilient.timeout", "TimeoutExhaustedException");

return CodeBlock.builder().add("""
var _circuitBreaker = $L;
try {
_circuitBreaker.acquire();
$L;
_circuitBreaker.releaseOnSuccess();
$L;
} catch (ru.tinkoff.kora.resilient.circuitbreaker.CallNotPermittedException e) {
} catch ($T e) {
throw e;
} catch (Exception e) {
_circuitBreaker.releaseOnError(e);
throw e;
}
""", circuitBreakerField, methodCall.toString(), returnCall.toString()).build();
""", circuitBreakerField, methodCall.toString(), returnCall.toString(), cbException).build();
}

private CodeBlock buildBodyMono(ExecutableElement method, String superCall, String circuitBreakerField) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ public ApplyResult apply(ExecutableElement method, String superCall, AspectConte
.map(e -> String.valueOf(e.getValue().getValue())).findFirst())
.orElseThrow();

var managerType = env.getTypeUtils().getDeclaredType(env.getElementUtils().getTypeElement("ru.tinkoff.kora.resilient.fallback.FallbackerManager"));
var managerType = env.getTypeUtils().getDeclaredType(env.getElementUtils().getTypeElement("ru.tinkoff.kora.resilient.fallback.FallbackManager"));
var fieldManager = aspectContext.fieldFactory().constructorParam(managerType, List.of());
var fallbackerType = env.getTypeUtils().getDeclaredType(env.getElementUtils().getTypeElement("ru.tinkoff.kora.resilient.fallback.Fallbacker"));
var fieldFallbacker = aspectContext.fieldFactory().constructorInitialized(
fallbackerType, CodeBlock.of("$L.get($S);", fieldManager, name));
var fallbackType = env.getTypeUtils().getDeclaredType(env.getElementUtils().getTypeElement("ru.tinkoff.kora.resilient.fallback.Fallback"));
var fieldFallback = aspectContext.fieldFactory().constructorInitialized(
fallbackType, CodeBlock.of("$L.get($S);", fieldManager, name));

final CodeBlock body;
if (MethodUtils.isMono(method)) {
body = buildBodyMono(method, fallback, superCall, fieldFallbacker);
body = buildBodyMono(method, fallback, superCall, fieldFallback);
} else if (MethodUtils.isFlux(method)) {
body = buildBodyFlux(method, fallback, superCall, fieldFallbacker);
body = buildBodyFlux(method, fallback, superCall, fieldFallback);
} else {
body = buildBodySync(method, fallback, superCall, fieldFallbacker);
body = buildBodySync(method, fallback, superCall, fieldFallback);
}

return new ApplyResult.MethodBody(body);
Expand Down Expand Up @@ -120,8 +120,4 @@ private CodeBlock buildBodyFlux(ExecutableElement method, FallbackMeta fallbackC
private CodeBlock buildMethodCall(ExecutableElement method, String call) {
return method.getParameters().stream().map(p -> CodeBlock.of("$L", p)).collect(joining(", ", call + "(", ")"));
}

private CodeBlock buildMethodSupplier(ExecutableElement method, String call) {
return method.getParameters().stream().map(p -> CodeBlock.of("$L", p)).collect(joining(", ", "() -> " + call + "(", ")"));
}
}
Loading

0 comments on commit 162016f

Please sign in to comment.