1
1
package org .hypertrace .circuitbreaker .grpcutils .resilience ;
2
2
3
3
import com .google .common .annotations .VisibleForTesting ;
4
- import com .google .inject .Singleton ;
5
- import com .typesafe .config .Config ;
6
4
import io .github .resilience4j .circuitbreaker .CircuitBreaker ;
7
5
import io .github .resilience4j .circuitbreaker .CircuitBreakerConfig ;
8
6
import io .github .resilience4j .circuitbreaker .CircuitBreakerRegistry ;
20
18
import java .util .Map ;
21
19
import java .util .concurrent .TimeUnit ;
22
20
import lombok .extern .slf4j .Slf4j ;
23
- import org .hypertrace .circuitbreaker .grpcutils .CircuitBreakerConfigProvider ;
21
+ import org .hypertrace .circuitbreaker .grpcutils .CircuitBreakerConfiguration ;
24
22
import org .hypertrace .circuitbreaker .grpcutils .CircuitBreakerInterceptor ;
23
+ import org .hypertrace .core .grpcutils .context .RequestContext ;
25
24
26
25
@ Slf4j
27
- @ Singleton
28
26
public class ResilienceCircuitBreakerInterceptor extends CircuitBreakerInterceptor {
29
27
30
- public static final CallOptions .Key <String > CIRCUIT_BREAKER_KEY =
31
- CallOptions .Key .createWithDefault ("circuitBreakerKey" , "default" );
32
28
private final CircuitBreakerRegistry resilicenceCircuitBreakerRegistry ;
33
- private final CircuitBreakerConfigProvider circuitBreakerConfigProvider ;
34
- private final Map <String , CircuitBreakerConfig > resilienceCircuitBreakerConfig ;
29
+ private final Map <String , CircuitBreakerConfig > resilienceCircuitBreakerConfigMap ;
35
30
private final ResilienceCircuitBreakerProvider resilienceCircuitBreakerProvider ;
31
+ private final CircuitBreakerConfiguration <?> circuitBreakerConfiguration ;
36
32
private final Clock clock ;
37
33
38
- public ResilienceCircuitBreakerInterceptor (Config config , Clock clock ) {
39
- this .circuitBreakerConfigProvider = new CircuitBreakerConfigProvider (config );
40
- this .resilienceCircuitBreakerConfig =
34
+ public ResilienceCircuitBreakerInterceptor (
35
+ CircuitBreakerConfiguration <?> circuitBreakerConfiguration , Clock clock ) {
36
+ this .circuitBreakerConfiguration = circuitBreakerConfiguration ;
37
+ this .clock = clock ;
38
+ this .resilienceCircuitBreakerConfigMap =
41
39
ResilienceCircuitBreakerConfigParser .getCircuitBreakerConfigs (
42
- circuitBreakerConfigProvider . getConfigMap ());
40
+ circuitBreakerConfiguration . getCircuitBreakerThresholdsMap ());
43
41
this .resilicenceCircuitBreakerRegistry =
44
- new ResilienceCircuitBreakerRegistryProvider (resilienceCircuitBreakerConfig )
42
+ new ResilienceCircuitBreakerRegistryProvider (resilienceCircuitBreakerConfigMap )
45
43
.getCircuitBreakerRegistry ();
46
44
this .resilienceCircuitBreakerProvider =
47
45
new ResilienceCircuitBreakerProvider (
48
- resilicenceCircuitBreakerRegistry , resilienceCircuitBreakerConfig );
49
- this .clock = clock ;
46
+ resilicenceCircuitBreakerRegistry , resilienceCircuitBreakerConfigMap );
50
47
}
51
48
52
49
@ VisibleForTesting
53
50
public ResilienceCircuitBreakerInterceptor (
54
- Config config ,
55
51
Clock clock ,
56
52
CircuitBreakerRegistry resilicenceCircuitBreakerRegistry ,
57
- ResilienceCircuitBreakerProvider resilienceCircuitBreakerProvider ) {
58
- this .circuitBreakerConfigProvider = new CircuitBreakerConfigProvider (config );
59
- this .resilienceCircuitBreakerConfig =
53
+ ResilienceCircuitBreakerProvider resilienceCircuitBreakerProvider ,
54
+ CircuitBreakerConfiguration <?> circuitBreakerConfiguration ) {
55
+ this .circuitBreakerConfiguration = circuitBreakerConfiguration ;
56
+ this .resilienceCircuitBreakerConfigMap =
60
57
ResilienceCircuitBreakerConfigParser .getCircuitBreakerConfigs (
61
- circuitBreakerConfigProvider . getConfigMap ());
58
+ circuitBreakerConfiguration . getCircuitBreakerThresholdsMap ());
62
59
this .resilicenceCircuitBreakerRegistry = resilicenceCircuitBreakerRegistry ;
63
60
this .resilienceCircuitBreakerProvider = resilienceCircuitBreakerProvider ;
64
61
this .clock = clock ;
65
62
}
66
63
67
64
@ Override
68
65
protected boolean isCircuitBreakerEnabled () {
69
- return circuitBreakerConfigProvider . isCircuitBreakerEnabled ();
66
+ return circuitBreakerConfiguration . isEnabled ();
70
67
}
71
68
72
69
@ Override
73
70
protected <ReqT , RespT > ClientCall <ReqT , RespT > createInterceptedCall (
74
71
MethodDescriptor <ReqT , RespT > method , CallOptions callOptions , Channel next ) {
75
- // Get circuit breaker key from CallOptions
76
- String circuitBreakerKey = callOptions .getOption (CIRCUIT_BREAKER_KEY );
77
- CircuitBreaker circuitBreaker =
78
- resilienceCircuitBreakerProvider .getCircuitBreaker (circuitBreakerKey );
79
72
return new ForwardingClientCall .SimpleForwardingClientCall <>(
80
73
next .newCall (method , callOptions )) {
74
+ CircuitBreaker circuitBreaker ;
75
+ String circuitBreakerKey ;
76
+
81
77
@ Override
82
78
public void start (Listener <RespT > responseListener , Metadata headers ) {
83
79
Instant startTime = clock .instant ();
@@ -87,8 +83,22 @@ public void start(Listener<RespT> responseListener, Metadata headers) {
87
83
super .start (wrappedListener , headers );
88
84
}
89
85
86
+ @ SuppressWarnings ("unchecked" )
90
87
@ Override
91
88
public void sendMessage (ReqT message ) {
89
+ CircuitBreakerConfiguration <ReqT > config =
90
+ (CircuitBreakerConfiguration <ReqT >) circuitBreakerConfiguration ;
91
+ if (config .getRequestClass () == null
92
+ || (!message .getClass ().equals (config .getRequestClass ()))) {
93
+ log .warn ("Invalid config for message type: {}" , message .getClass ());
94
+ super .sendMessage (message );
95
+ }
96
+ if (config .getKeyFunction () != null ) {
97
+ circuitBreakerKey = config .getKeyFunction ().apply (RequestContext .CURRENT .get (), message );
98
+ } else {
99
+ circuitBreakerKey = "default" ;
100
+ }
101
+ circuitBreaker = resilienceCircuitBreakerProvider .getCircuitBreaker (circuitBreakerKey );
92
102
if (!circuitBreaker .tryAcquirePermission ()) {
93
103
logCircuitBreakerRejection (circuitBreakerKey , circuitBreaker );
94
104
String rejectionReason =
0 commit comments