/* ******************************************************************************* * Copyright (c) 2016-2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. * * Licensed under the Apache License, Version 2.0 (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package org.eclipse.microprofile.fault.tolerance.tck.circuitbreaker.clientserver; import java.io.Serializable; import java.sql.Connection; import javax.enterprise.context.RequestScoped; import org.eclipse.microprofile.fault.tolerance.tck.util.TCKConfig; import org.eclipse.microprofile.fault.tolerance.tck.util.TestException; import org.eclipse.microprofile.faulttolerance.CircuitBreaker; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException; import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; /** * A client to exercise Circuit Breaker thresholds using Retries. * * @author <a href="mailto:[email protected]">Neil Young</a> * @author <a href="mailto:[email protected]">Andrew Rouse</a> */ @RequestScoped public class CircuitBreakerClientWithRetry implements Serializable { private int counterForInvokingServiceA = 0; private int counterForInvokingServiceB = 0; private int counterForInvokingServiceC = 0; public int getCounterForInvokingServiceA() { return counterForInvokingServiceA; } public int getCounterForInvokingServiceB() { return counterForInvokingServiceB; } public int getCounterForInvokingServiceC() { return counterForInvokingServiceC; } @CircuitBreaker(successThreshold = 2, requestVolumeThreshold = 4, failureRatio = 0.75, delay = 50000) @Retry(retryOn = {RuntimeException.class}, maxRetries = 7) public Connection serviceA() { Connection conn = null; counterForInvokingServiceA++; conn = connectionService(); return conn; } @CircuitBreaker(successThreshold = 2, requestVolumeThreshold = 4, failureRatio = 0.75, delay = 50000) @Retry(retryOn = {RuntimeException.class}, maxRetries = 2) public Connection serviceB() { Connection conn = null; counterForInvokingServiceB++; conn = connectionService(); return conn; } /** * Configured to always time out and Retry until CircuitBreaker is triggered on 4th call. */ @CircuitBreaker(successThreshold = 2, requestVolumeThreshold = 4, failureRatio = 0.75, delay = 50000) @Retry(retryOn = {RuntimeException.class, TimeoutException.class}, maxRetries = 7, maxDuration = 20000) @Timeout(100) // Scaled via config public Connection serviceC() { Connection conn = null; counterForInvokingServiceC++; try { Thread.sleep(TCKConfig.getConfig().getTimeoutInMillis(5000)); throw new RuntimeException("Timeout did not interrupt"); } catch (InterruptedException e) { //expected } return conn; } /** * Has a CircuitBreaker and Retries on CircuitBreakerOpenException * * @param throwException whether this method should throw a TestException to simulate an application failure * @return string "OK" */ @CircuitBreaker(requestVolumeThreshold = 4, failureRatio = 0.75, delay = 1000) @Retry(retryOn = CircuitBreakerOpenException.class, maxRetries = 20, delay = 100, jitter = 0) // Scaled via config public String serviceWithRetryOnCbOpen(boolean throwException) { if (throwException) { throw new TestException(); } else { return "OK"; } } /** * Has a CircuitBreaker and Retries on TimeoutException * <p> * The method should never throw a TimeoutException so the retry should have no effect * * @param throwException whether this method should throw a TestException to simulate an application failure * @return string "OK" */ @CircuitBreaker(requestVolumeThreshold = 4, failureRatio = 0.75, delay = 1000) @Retry(retryOn = TimeoutException.class, maxRetries = 20, delay = 200) // Scaled via config public String serviceWithRetryOnTimeout(boolean throwException) { if (throwException) { throw new TestException(); } else { return "OK"; } } /** * Has a CircuitBreaker and Retries on all exceptions except TestException and CircuitBreakerOpenException * * @param throwException whether this method should throw a TestException to simulate an application failure * @return string "OK" */ @CircuitBreaker(requestVolumeThreshold = 4, failureRatio = 0.75, delay = 1000) @Retry(abortOn = { TestException.class, CircuitBreakerOpenException.class }, maxRetries = 20, delay = 200) // Scaled via config public String serviceWithRetryFailOnCbOpen(boolean throwException) { if (throwException) { throw new TestException(); } else { return "OK"; } } //simulate a backend service private Connection connectionService() { throw new RuntimeException("Connection failed"); } }