CircuitBreakerRpcClient extends AbstractCircuitBreakerClient<RpcRequest, RpcResponse> implements RpcClient { public static Function<? super RpcClient, CircuitBreakerRpcClient> newPerMethodDecorator(Function<String, ? extends CircuitBreaker> factory, CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent) { return newDecorator(CircuitBreakerMapping.perMethod(factory), ruleWithContent); } CircuitBreakerRpcClient(RpcClient delegate, CircuitBreakerMapping mapping,
                            CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static Function<? super RpcClient, CircuitBreakerRpcClient> newDecorator(CircuitBreaker circuitBreaker, CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static Function<? super RpcClient, CircuitBreakerRpcClient> newDecorator(CircuitBreakerMapping mapping, CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static Function<? super RpcClient, CircuitBreakerRpcClient> newPerMethodDecorator(Function<String, ? extends CircuitBreaker> factory,
                          CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static Function<? super RpcClient, CircuitBreakerRpcClient> newPerHostDecorator(Function<String, ? extends CircuitBreaker> factory,
                        CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static Function<? super RpcClient, CircuitBreakerRpcClient> newPerHostAndMethodDecorator(BiFunction<String, String, ? extends CircuitBreaker> factory,
                                 CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent); static CircuitBreakerRpcClientBuilder builder(
            CircuitBreakerRuleWithContent<RpcResponse> ruleWithContent);  }
@Test void testPerMethodDecorator() { final CircuitBreaker circuitBreaker = mock(CircuitBreaker.class); when(circuitBreaker.canRequest()).thenReturn(false); @SuppressWarnings("unchecked") final Function<String, CircuitBreaker> factory = mock(Function.class); when(factory.apply(any())).thenReturn(circuitBreaker); final int COUNT = 2; failFastInvocation(CircuitBreakerRpcClient.newPerMethodDecorator(factory, rule()), COUNT); verify(circuitBreaker, times(COUNT)).canRequest(); verify(factory, times(1)).apply("methodA"); }
@Test void testPerMethodScope() throws Exception { final AtomicLong ticker = new AtomicLong(); final Function<String, CircuitBreaker> factory = method -> buildCircuitBreaker(ticker::get); final RpcClient delegate = mock(RpcClient.class); when(delegate.execute(ctxA, reqA)).thenReturn(failureRes); when(delegate.execute(ctxB, reqB)).thenReturn(successRes); final CircuitBreakerRpcClient stub = CircuitBreakerRpcClient.newPerMethodDecorator(factory, rule()).apply(delegate); for (int i = 0; i < minimumRequestThreshold + 1; i++) { assertThatThrownBy(() -> stub.execute(ctxA, reqA).join()) .hasCauseInstanceOf(AnticipatedException.class); ticker.addAndGet(Duration.ofMillis(1).toNanos()); } assertThatThrownBy(() -> stub.execute(ctxA, reqA)).isInstanceOf(FailFastException.class); assertThat(stub.execute(ctxB, reqB).join()).isNull(); }