Try-catch is meant to help in the exception handling. This means somehow that it will help our system to be more robust: try to recover from an unexpected event.
We suspect something might happen when executing and instruction (sending a message), so it gets enclosed in the try. If that something nearly unexpected happens, we can do something: we write the catch. I don't think we called to just log the exception. I thing the catch block is meant to give us the opportunity of recovering from the error.
Now, let's say we recover from the error because we could fix what was wrong. It could be super nice to do a re-try:
try{ some_instruction(); }
catch (NearlyUnexpectedException e){
fix_the_problem();
retry;
}
This would quickly fall in the eternal loop, but let's say that the fix_the_problem returns true, then we retry. Given that there is no such thing in Java, how would YOU solve this problem? What would be your best design code for solving this?
This is like a philosophical question, given that I already know what I'm asking for is not directly supported by Java.
You need to enclose your try-catch inside a while loop like this: -
int count = 0;
int maxTries = 3;
while(true) {
try {
// Some Code
// break out of loop, or return, on success
} catch (SomeException e) {
// handle exception
if (++count == maxTries) throw e;
}
}
I have taken count and maxTries to avoid running into an infinite loop, in case the exception keeps on occurring in your try block.
Obligatory "enterprisy" solution:
public abstract class Operation {
abstract public void doIt();
public void handleException(Exception cause) {
//default impl: do nothing, log the exception, etc.
}
}
public class OperationHelper {
public static void doWithRetry(int maxAttempts, Operation operation) {
for (int count = 0; count < maxAttempts; count++) {
try {
operation.doIt();
count = maxAttempts; //don't retry
} catch (Exception e) {
operation.handleException(e);
}
}
}
}
And to call:
OperationHelper.doWithRetry(5, new Operation() {
#Override public void doIt() {
//do some stuff
}
#Override public void handleException(Exception cause) {
//recover from the Exception
}
});
As usual, the best design depends on the particular circumstances. Usually though, I write something like:
for (int retries = 0;; retries++) {
try {
return doSomething();
} catch (SomeException e) {
if (retries < 6) {
continue;
} else {
throw e;
}
}
}
You can use AOP and Java annotations from jcabi-aspects (I'm a developer):
#RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
return url.openConnection().getContent();
}
You could also use #Loggable and #LogException annotations.
Although try/catch into while is well-known and good strategy I want to suggest you recursive call:
void retry(int i, int limit) {
try {
} catch (SomeException e) {
// handle exception
if (i >= limit) {
throw e; // variant: wrap the exception, e.g. throw new RuntimeException(e);
}
retry(i++, limit);
}
}
Spring AOP and annotation based solution:
Usage (#RetryOperation is our custom annotation for the job):
#RetryOperation(retryCount = 1, waitSeconds = 10)
boolean someMethod() throws Exception {
}
We'll need two things to accomplish this: 1. an annotation interface, and 2. a spring aspect. Here's one way to implement these:
The Annotation Interface:
import java.lang.annotation.*;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface RetryOperation {
int retryCount();
int waitSeconds();
}
The Spring Aspect:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
#Aspect #Component
public class RetryAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(RetryAspect.class);
#Around(value = "#annotation(RetryOperation)")
public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable {
Object response = null;
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
RetryOperation annotation = method.getAnnotation(RetryOperation.class);
int retryCount = annotation.retryCount();
int waitSeconds = annotation.waitSeconds();
boolean successful = false;
do {
try {
response = joinPoint.proceed();
successful = true;
} catch (Exception ex) {
LOGGER.info("Operation failed, retries remaining: {}", retryCount);
retryCount--;
if (retryCount < 0) {
throw ex;
}
if (waitSeconds > 0) {
LOGGER.info("Waiting for {} second(s) before next retry", waitSeconds);
Thread.sleep(waitSeconds * 1000l);
}
}
} while (!successful);
return response;
}
}
Most of these answers are essentially the same. Mine is also, but this is the form I like
boolean completed = false;
Throwable lastException = null;
for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++)
{
try {
completed = some_operation();
break;
}
catch (UnlikelyException e) {
lastException = e;
fix_the_problem();
}
}
if (!completed) {
reportError(lastException);
}
Use a while loop with local status flag. Initialize the flag as false and set it to true when operation is successful e.g. below:
boolean success = false;
while(!success){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
This will keep retrying until its successful.
If you want to retry only certain number of times then use a counter as well:
boolean success = false;
int count = 0, MAX_TRIES = 10;
while(!success && count++ < MAX_TRIES){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
if(!success){
//It wasn't successful after 10 retries
}
This will try max 10 times if not successful until then an will exit if its successful before hand.
This is an old question but a solution is still relevant. Here is my generic solution in Java 8 without using any third party library:
public interface RetryConsumer<T> {
T evaluate() throws Throwable;
}
public interface RetryPredicate<T> {
boolean shouldRetry(T t);
}
public class RetryOperation<T> {
private RetryConsumer<T> retryConsumer;
private int noOfRetry;
private int delayInterval;
private TimeUnit timeUnit;
private RetryPredicate<T> retryPredicate;
private List<Class<? extends Throwable>> exceptionList;
public static class OperationBuilder<T> {
private RetryConsumer<T> iRetryConsumer;
private int iNoOfRetry;
private int iDelayInterval;
private TimeUnit iTimeUnit;
private RetryPredicate<T> iRetryPredicate;
private Class<? extends Throwable>[] exceptionClasses;
private OperationBuilder() {
}
public OperationBuilder<T> retryConsumer(final RetryConsumer<T> retryConsumer) {
this.iRetryConsumer = retryConsumer;
return this;
}
public OperationBuilder<T> noOfRetry(final int noOfRetry) {
this.iNoOfRetry = noOfRetry;
return this;
}
public OperationBuilder<T> delayInterval(final int delayInterval, final TimeUnit timeUnit) {
this.iDelayInterval = delayInterval;
this.iTimeUnit = timeUnit;
return this;
}
public OperationBuilder<T> retryPredicate(final RetryPredicate<T> retryPredicate) {
this.iRetryPredicate = retryPredicate;
return this;
}
#SafeVarargs
public final OperationBuilder<T> retryOn(final Class<? extends Throwable>... exceptionClasses) {
this.exceptionClasses = exceptionClasses;
return this;
}
public RetryOperation<T> build() {
if (Objects.isNull(iRetryConsumer)) {
throw new RuntimeException("'#retryConsumer:RetryConsumer<T>' not set");
}
List<Class<? extends Throwable>> exceptionList = new ArrayList<>();
if (Objects.nonNull(exceptionClasses) && exceptionClasses.length > 0) {
exceptionList = Arrays.asList(exceptionClasses);
}
iNoOfRetry = iNoOfRetry == 0 ? 1 : 0;
iTimeUnit = Objects.isNull(iTimeUnit) ? TimeUnit.MILLISECONDS : iTimeUnit;
return new RetryOperation<>(iRetryConsumer, iNoOfRetry, iDelayInterval, iTimeUnit, iRetryPredicate, exceptionList);
}
}
public static <T> OperationBuilder<T> newBuilder() {
return new OperationBuilder<>();
}
private RetryOperation(RetryConsumer<T> retryConsumer, int noOfRetry, int delayInterval, TimeUnit timeUnit,
RetryPredicate<T> retryPredicate, List<Class<? extends Throwable>> exceptionList) {
this.retryConsumer = retryConsumer;
this.noOfRetry = noOfRetry;
this.delayInterval = delayInterval;
this.timeUnit = timeUnit;
this.retryPredicate = retryPredicate;
this.exceptionList = exceptionList;
}
public T retry() throws Throwable {
T result = null;
int retries = 0;
while (retries < noOfRetry) {
try {
result = retryConsumer.evaluate();
if (Objects.nonNull(retryPredicate)) {
boolean shouldItRetry = retryPredicate.shouldRetry(result);
if (shouldItRetry) {
retries = increaseRetryCountAndSleep(retries);
} else {
return result;
}
} else {
// no retry condition defined, no exception thrown. This is the desired result.
return result;
}
} catch (Throwable e) {
retries = handleException(retries, e);
}
}
return result;
}
private int handleException(int retries, Throwable e) throws Throwable {
if (exceptionList.contains(e.getClass()) || (exceptionList.isEmpty())) {
// exception is excepted, continue retry.
retries = increaseRetryCountAndSleep(retries);
if (retries == noOfRetry) {
// evaluation is throwing exception, no more retry left. Throw it.
throw e;
}
} else {
// unexpected exception, no retry required. Throw it.
throw e;
}
return retries;
}
private int increaseRetryCountAndSleep(int retries) {
retries++;
if (retries < noOfRetry && delayInterval > 0) {
try {
timeUnit.sleep(delayInterval);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
}
return retries;
}
}
Let's have a test case like:
#Test
public void withPredicateAndException() {
AtomicInteger integer = new AtomicInteger();
try {
Integer result = RetryOperation.<Integer>newBuilder()
.retryConsumer(() -> {
int i = integer.incrementAndGet();
if (i % 2 == 1) {
throw new NumberFormatException("Very odd exception");
} else {
return i;
}
})
.noOfRetry(10)
.delayInterval(10, TimeUnit.MILLISECONDS)
.retryPredicate(value -> value <= 6)
.retryOn(NumberFormatException.class, EOFException.class)
.build()
.retry();
Assert.assertEquals(8, result.intValue());
} catch (Throwable throwable) {
Assert.fail();
}
}
A simple way to solve the issue would be to wrap the try/catch in a while loop and maintain a count. This way you could prevent an infinite loop by checking a count against some other variable while maintaining a log of your failures. It isn't the most exquisite solution, but it would work.
In case it's useful, a couple more options to consider, all thrown together (stopfile instead of retries, sleep, continue larger loop) all possibly helpful.
bigLoop:
while(!stopFileExists()) {
try {
// do work
break;
}
catch (ExpectedExceptionType e) {
// could sleep in here, too.
// another option would be to "restart" some bigger loop, like
continue bigLoop;
}
// ... more work
}
If not all exceptions warrant a retry, only some. And if at least one try has to be made, Here is an alternative utility method:
void runWithRetry(Runnable runnable, Class<Exception> exClass, int maxRetries) {
Exception err = null;
do {
maxRetries--;
try {
runnable.run();
err = null;
} catch (Exception e) {
if(exClass.isAssignableFrom(e.getClass())){
err = e;
}else {
throw e;
}
}
} while (err != null && maxRetries > 0);
if (err != null) {
throw err;
}
}
Usage:
runWithRetry(() -> {
// do something
}, TimeoutException.class, 5)
All a Try-Catch does is allow your program to fail gracefully. In a catch statement, you generally try to log the error, and maybe roll back changes if you need to.
bool finished = false;
while(finished == false)
{
try
{
//your code here
finished = true
}
catch(exception ex)
{
log.error("there was an error, ex");
}
}
Use a do-while to design re-try block.
boolean successful = false;
int maxTries = 3;
do{
try {
something();
success = true;
} catch(Me ifUCan) {
maxTries--;
}
} while (!successful || maxTries > 0)
Here a reusable and more generic approach for Java 8+ that does not require external libraries:
public interface IUnreliable<T extends Exception>
{
void tryRun ( ) throws T;
}
public static <T extends Exception> void retry (int retryCount, IUnreliable<T> runnable) throws T {
for (int retries = 0;; retries++) {
try {
runnable.tryRun();
return;
} catch (Exception e) {
if (retries < retryCount) {
continue;
} else {
throw e;
}
}
}
}
Usage:
#Test
public void demo() throws IOException {
retry(3, () -> {
new File("/tmp/test.txt").createNewFile();
});
}
You can use https://github.com/bnsd55/RetryCatch
Example:
RetryCatch retryCatchSyncRunnable = new RetryCatch();
retryCatchSyncRunnable
// For infinite retry times, just remove this row
.retryCount(3)
// For retrying on all exceptions, just remove this row
.retryOn(ArithmeticException.class, IndexOutOfBoundsException.class)
.onSuccess(() -> System.out.println("Success, There is no result because this is a runnable."))
.onRetry((retryCount, e) -> System.out.println("Retry count: " + retryCount + ", Exception message: " + e.getMessage()))
.onFailure(e -> System.out.println("Failure: Exception message: " + e.getMessage()))
.run(new ExampleRunnable());
Instead of new ExampleRunnable() you can pass your own anonymous function.
Simplifying #ach's previous solution into one file and using functional interfaces.
public class OperationHelper {
public static void doWithRetry(int maxAttempts, Runnable operation, Consumer<Exception> handle) {
for (int count = 0; count < maxAttempts; count++) {
try {
operation.run();
count = maxAttempts; //don't retry
} catch (Exception e) {
handle.accept(e);
}
}
}
}
simple
int MAX = 3;
int count = 0;
while (true) {
try {
...
break;
} catch (Exception e) {
if (count++ < MAX) {
continue;
}
...
break;
}
}
https://onlinegdb.com/a-7RsL1Gh
public void doSomething() throws Exception{
final int MAX_TRIES = 10;
int count = 0;
while(count++ < MAX_TRIES){
try{
System.out.println("trying");
causeIssue(count); // throws error/exception till count 2
System.out.println("trying successful");
break; // break on success
} catch (Exception e){
System.out.println("caught, logging Exception:" + count);
} catch (Error e){
System.out.println("caught, logging Error:" + count);
}
}
}
Output:
trying
caught, logging Error:1
trying
caught, logging Error:2
trying
trying successful
I know there are already many similar answers here, and mine is not much different, but I will post it anyway because it deals with a specific case/issue.
When dealing with the facebook Graph API in PHP you sometimes get an error, but immediately re-trying the same thing will give a positive result (for various magical Internet reasons that are beyond the scope of this question). In this case there is no need to fix any error, but to simply try again because there was some kind of "facebook error".
This code is used immediately after creating a facebook session:
//try more than once because sometimes "facebook error"
$attempt = 3;
while($attempt-- > 0)
{
// To validate the session:
try
{
$facebook_session->validate();
$attempt = 0;
}
catch (Facebook\FacebookRequestException $ex)
{
// Session not valid, Graph API returned an exception with the reason.
if($attempt <= 0){ echo $ex->getMessage(); }
}
catch (\Exception $ex)
{
// Graph API returned info, but it may mismatch the current app or have expired.
if($attempt <= 0){ echo $ex->getMessage(); }
}
}
Also, by having the for loop count down to zero ($attempt--) it makes it pretty easy to change the number of attempts in the future.
following is my solution with very simple approach!
while (true) {
try {
/// Statement what may cause an error;
break;
} catch (Exception e) {
}
}
Im not sure if this is the "Professional" way to do it and i'm not entirely sure if it works for everything.
boolean gotError = false;
do {
try {
// Code You're Trying
} catch ( FileNotFoundException ex ) {
// Exception
gotError = true;
}
} while ( gotError = true );
https://github.com/tusharmndr/retry-function-wrapper/tree/master/src/main/java/io
int MAX_RETRY = 3;
RetryUtil.<Boolean>retry(MAX_RETRY,() -> {
//Function to retry
return true;
});
The issue with the remaining solutions is that, the correspondent function tries continuously without a time interval in-between, thus over flooding the stack.
Why not just trying only every second and ad eternum?
Here a solution using setTimeout and a recursive function:
(function(){
try{
Run(); //tries for the 1st time, but Run() as function is not yet defined
}
catch(e){
(function retry(){
setTimeout(function(){
try{
console.log("trying...");
Run();
console.log("success!");
}
catch(e){
retry(); //calls recursively
}
}, 1000); //tries every second
}());
}
})();
//after 5 seconds, defines Run as a global function
var Run;
setTimeout(function(){
Run = function(){};
}, 5000);
Replace the function Run() by the function or code that you'd like to retry every second.
Give it a try using springs #Retryable annotation , the below method will retry for 3 attempts when RuntimeException occurs
#Retryable(maxAttempts=3,value= {RuntimeException.class},backoff = #Backoff(delay = 500))
public void checkSpringRetry(String str) {
if(StringUtils.equalsIgnoreCase(str, "R")) {
LOGGER.info("Inside retry.....!!");
throw new RuntimeException();
}
}
Below snippet execute some code snippet. If you got any error while executing the code snippet, sleep for M milliseconds and retry. Reference link.
public void retryAndExecuteErrorProneCode(int noOfTimesToRetry, CodeSnippet codeSnippet, int sleepTimeInMillis)
throws InterruptedException {
int currentExecutionCount = 0;
boolean codeExecuted = false;
while (currentExecutionCount < noOfTimesToRetry) {
try {
codeSnippet.errorProneCode();
System.out.println("Code executed successfully!!!!");
codeExecuted = true;
break;
} catch (Exception e) {
// Retry after 100 milliseconds
TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
System.out.println(e.getMessage());
} finally {
currentExecutionCount++;
}
}
if (!codeExecuted)
throw new RuntimeException("Can't execute the code within given retries : " + noOfTimesToRetry);
}
Here is my solution similar to some others can wrap a function, but allows you to get the functions return value, if it suceeds.
/**
* Wraps a function with retry logic allowing exceptions to be caught and retires made.
*
* #param function the function to retry
* #param maxRetries maximum number of retires before failing
* #param delay time to wait between each retry
* #param allowedExceptionTypes exception types where if caught a retry will be performed
* #param <V> return type of the function
* #return the value returned by the function if successful
* #throws Exception Either an unexpected exception from the function or a {#link RuntimeException} if maxRetries is exceeded
*/
#SafeVarargs
public static <V> V runWithRetriesAndDelay(Callable<V> function, int maxRetries, Duration delay, Class<? extends Exception>... allowedExceptionTypes) throws Exception {
final Set<Class<? extends Exception>> exceptions = new HashSet<>(Arrays.asList(allowedExceptionTypes));
for(int i = 1; i <= maxRetries; i++) {
try {
return function.call();
} catch (Exception e) {
if(exceptions.contains(e.getClass())){
// An exception of an expected type
System.out.println("Attempt [" + i + "/" + maxRetries + "] Caught exception [" + e.getClass() + "]");
// Pause for the delay time
Thread.sleep(delay.toMillis());
}else {
// An unexpected exception type
throw e;
}
}
}
throw new RuntimeException(maxRetries + " retries exceeded");
}
This Solution allows you to configure a reusable functionality for retrying based on certain exception without using any external libraries
// Create a Function that suits your need .
#FunctionalInterface
public interface ThrowableBiFunction<U,T,R> {
R apply(U u ,T t) throws Exception;
}
//Here's the crux of the solution
public interface ExceptionRetryable<T, U, R> {
int getRetries();
List<Class<? extends Exception>> getRetryableExceptions();
default R execute(ThrowableBiFunction<T, U, R> function, T t, U u) throws Exception {
int numberOfRetries = getRetries();
return execute(function, t, u, numberOfRetries);
}
default R execute(ThrowableBiFunction<T, U, R> function, T t, U u, int retryCount) throws Exception {
try {
log.info(" Attempting to execute ExceptionRetryable#execute ,Number of remaining retries {} ",retryCount);
return function.apply(t, u);
} catch (Exception e) {
log.info(" error occurred in ExceptionRetryable#execute",e);
if (retryCount == 0)
throw e;
for (Class exp : getRetryableExceptions()) {
if (e.getClass() == exp) {
return execute(function, t, u, retryCount - 1);
}
}
throw e;
}
}
}
// create an implementation for exception retryable
public class TestRetryable implements ExceptionRetryable<String, String, List<String>> {
#Override
public int getRetries() {
return 10;
}
#Override
public List<Class<? extends Exception>> getRetryableExceptions() {
return Arrays.asList(new Exception1().getClass(), new Exception2().getClass());
;
}
}
// Finally create a ThrowableBiFunction that encapsulates that piece of code that needs to be retried on exception and an instance of ExceptionRetryable
TestRetryable retryable = new TestRetryable();
ThrowableBiFunction<Integer,Long, String> testRetrablefcn = { i, l ->
// your code goes here
};
Integer i = 0;
Long l = 1l;
String output = testRetrablefcn.execute(testRetrablefcn,i,l);
Production ready code:
#FunctionalInterface
public interface Operation {
void doCall() throws IOException;
default void handleException(Exception e) {
//Your custom default implementation
}
public class OperationHelper {
public static void doWithRetry(int maxAttempts, Operation operation) {
for (int count = 0; count <= maxAttempts; count++) {
try {
operation.doCall();
return;
} catch (Exception e) {
if (count == maxAttempts) {
e.printStackTrace();
return;
} else {
operation.handleException(e);
}
}
}
}
}
Usage with default implementation in code:
OperationHelper.doWithRetry(10,
() -> //do your job );
Usage when custom exception handle is needed:
OperationHelper.doWithRetry(10, new Operation() {
#Override public void doIt() {
//do some stuff
}
#Override public void handleException(Exception cause) {
//recover from the Exception
}
});
Related
My situation
I'm trying to craft a functionality which would execute n (where n >=0) requests to a given endpoint, but I do understand that sometimes that endpoint might not respond due to
500 error or other issue, so I want to repeat my requests to an endpoint (with a
small interval in between [not yet implemented]) till I get a response, or till I get an unknown error which would indicate what I can't repeat, because of other reasons than a crashed server.
So, I've tried to implement this piece of functionality using Executors and concurrency provided by Java 11 and it does not work as I want
I can't resubmit failed tasks till I get all the responses and I don't know why
I have a method
private void DoMyTasks(List<MyRequest> requests) {
final ExecutorService executorService = Executors.newFixedThreadPool(10);
final ExecutorCompletionService<MyReqResDto> completionService =
new ExecutorCompletionService<>(executorService);
for (final MyRequest MyRequest : requests) {
completionService.submit(new MyCallableRequest(webClient, MyRequest));
}
List<MyReqResDto> responses = new ArrayList<>();
for (int i = 0; i < requests.size(); ++i) {
try {
final Future<MyReqResDto> future = completionService.take();
if (future.get().getEx() != null) {
completionService.submit(new MyCallableRequest(webClient, future.get().getMyRequest()));
}
responses.add(future.get());
} catch (ExecutionException | InterruptedException e) {
log.warn("Error"));
} catch (Exception exception) {
log.error("Other error");
} finally {
executorService.shutdown();
try {
if (!executorService.awaitTermination(10, TimeUnit.MINUTES)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
}
}
responses.size();
}
I'm trying to repeat failed tasks with
if (future.get().getEx() != null) {
completionService.submit(new MyCallableRequest(webClient, future.get().getMyRequest()));
}
and yet, at the end of execution I don't get all responses for my requests. What I get is at most 3 to 5 responses when I try executing 10 requests. Why? How to fix it?
My callable class is
public class MyCallableRequest implements Callable<MyReqResDto> {
private final WebClient webClient;
private final MyRequest myRequest;
public MyCallableRequest(WebClient webClient, MyRequest myRequest) {
this.webClient = webClient;
this.myRequest = myRequest;
}
#Override
public MyReqResDto call() throws Exception {
try {
if (new Random().nextInt(10) % 2 == 0) {
throw new TestException();
}
if (new Random().nextInt(10) % 7 == 0) {
throw new RuntimeException();
}
WebClient.UriSpec<WebClient.RequestBodySpec> uriSpec = webClient.post();
WebClient.RequestBodySpec bodySpec = uriSpec.uri(
s -> s.path("/myEndpoint").build());
MyRequestDto myMyRequestDto = new MyRequestDto();
WebClient.RequestHeadersSpec<?> headersSpec =
bodySpec.body(Mono.just(myMyRequestDto), MyRequestDto.class);
ResponseDto responseDto = headersSpec.exchangeToMono(s -> {
if (s.statusCode().equals(HttpStatus.OK)) {
return s.bodyToMono(ResponseDto.class);
} else if (s.statusCode().is1xxInformational()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is3xxRedirection()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is4xxClientError()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is5xxServerError()) {
return s.createException().flatMap(Mono::error);
} else {
return s.createException().flatMap(Mono::error);
}
//return null;
}).block();
return new MyReqResDto(myRequest, responseDto, null);
} catch (Exception exception) {
return new MyReqResDto(myRequest, null, exception);
}
}
}
Update NO. 1
I changed a for loop to a while loop according to a comment provided by
Slaw and an answer provided by erickson. And this solutions works, meaning that
it is hammering an endpoint till all responses are received without
any errors. But I'm still not sure it feels that I'm building a sh**
tower with this solution. Is there any thread related issues that I should be aware while using executor like this?
while (true) {
Future < MyReqResDto > future = null;
try {
future = completionService.take();
if (future.get().getEx() != null /*and check exception if possible to handle, if not break from a loop*/) {
completionService.submit(new MyCallableRequest(webClient, future.get().getRequestCT());
} else {
responseDtos.add(future.get());
}
} catch (ExecutionException | InterruptedException e) {
log.warn("Error while downloading", e.getCause());
// test if I can recover from these exceptions if no
break;
}
}
if (responseDtos.size() == requests.size()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(10, TimeUnit.MINUTES)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
break;
}
You are shutting down the executor as soon as you get one response. Perhaps a few more have completed in this time, but you are not allowing time for any others to complete.
Your logic here is wrong. The executor should only be shut down when you are sure no more tasks will be submitted; at soonest, that is after the loop responsible for re-submitting failures.
Here is a simplified view of your code to highlight the premature shutdown:
for (int i = 0; i < requests.size(); ++i) {
try {
final Future<MyReqResDto> future = completionService.take();
...
responses.add(future.get());
...
} finally {
executorService.shutdown();
}
}
I need to write a simple code tester program, but I got stuck comparing the given error class with the test expected class. I am supposed to use reflection in this exercise.
I have my code testing class:
public class TestRunner {
private String result = "";
public void runTests(List<String> testClassNames) {
for (String testClassName : testClassNames) {
Class<?> clazz;
try {
clazz = Class.forName(testClassName);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("No such class.");
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyTest.class) != null) {
if (testClassName.equals("reflection.tester.ExampleTests1")) {
result += method.getName() + "() - ";
ExampleTests1 instance = new ExampleTests1();
try {
// if null, result = OK
method.invoke(instance);
result += "OK\n";
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
// if error is caught result = FAILED
result += "FAILED\n";
}
} else {
// the second class. should only return "OK" if the error is implemented from the exception class
result += method.getName() + "() - ";
ExampleTests2 instance = new ExampleTests2();
try {
method.invoke(instance);
result += "FAILED\n";
} catch (RuntimeException e) {
Throwable original = e.getCause();
Object expected = method.getReturnType();
if (original.getClass().isAssignableFrom(expected.getClass())) {
result += "OK\n";
} else {
result += "FAILED\n";
}
} catch (InvocationTargetException | IllegalAccessException e) {
result += "ERROR\n";
}
}
}
}
}
}
}
Also have two test classes. In the first one there is only one rule, if the test won't throw an exception the test should pass, and it is working. The second class is more complicated. If the thrown error class is implemented or same to the expected error class then the test should pass and OK should be added to the result. Currently my code won't catch RunTimeException at all and moves to the last catch block. How can I fix this?
I will also add the test class for more information.
public class ExampleTests2 {
#MyTest(expected = RuntimeException.class)
public void test3() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test4() {
throw new RuntimeException();
}
#MyTest(expected = IllegalStateException.class)
public void test5() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test6() {
}
public void helperMethod() {
}
}
test3() and test5() should pass, test4() and test6() should fail, helperMethod() won't be checked because I only need to use the tests with #MyTest annotation.
JUnit has an assertThrows method that checks that an Exception is thrown. It has a method signature of
static <T extends Throwable> assertThrows​(Class<T> expectedType, Executable executable){}
Here's the documentation: https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html#assertThrows(java.lang.Class,org.junit.jupiter.api.function.Executable)
and here's how JUnit implements it:
https://github.com/junit-team/junit5/blob/main/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java
I put a simple retry because the operation can rarely fail. The simplified code is below. The method putObject can accidentally throw an exception, in this case the retry should allow to invoke this method again. Is it possible to write a JUnit test for this?
I know that with Mockito library we can force to throw an Exception invoking a method but how to force this exception to be thrown only once?
public class RetryExample {
Bucket bucket = new Bucket();
static int INTERNAL_EXCEPTION_CODE = 100;
class AException extends RuntimeException {
private static final long serialVersionUID = 1L;
int statusCode;
public int getStatusCode() {
return statusCode;
}
}
class Bucket {
public void putObject(String fileName, byte[] data) throws AException {
System.out.println("PutObject=" + fileName + " data=" + data);
}
}
public void process(String fileName, byte[] data) throws AException {
try {
retryOperation((f, d) -> bucket.putObject(f, d), fileName, data);
} catch (Exception ex) {
throw new AException("Failed to write data", ex);
}
}
private <T, U> void retryOperation(BiConsumer<T, U> biConsumer, T t, U u) {
int retries = 0;
boolean retry = false;
AException lastServiceException = null;
do {
try {
biConsumer.accept(t, u);
} catch (AException e) {
lastServiceException = e;
int statusCode = e.getStatusCode();
if (statusCode == INTERNAL_EXCEPTION_CODE) {
throw e;
} else {
break;
}
}
retries++;
if (retries >= 3) {
retry = false;
}
} while (retry);
if (lastServiceException != null) {
throw lastServiceException;
}
}
Test Class:
public class RetryExampleTest {
...
#Test
public void test() {
RetryExample retryExample = new RetryExample();
String fileName = "TestFile";
byte[] data = simulatedPayload(10000);
try {
retryExample.process(fileName, data);
} catch (Exception e) {
fail("Exception thrown=" + e);
}
}
According to the Mockito documentation you can set different behavior for consecutive method calls.
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
In case of a void method you can do something similar (Mockito documentation)
doThrow(new RuntimeException())
.doNothing()
.when(mock).doSomething();
I think you can use a global data object to store the times of throw Exceptions, so in the Mockito library invoke the Exception method just taken the global data object to record the times. It would be simple. Just all by your control.
I'm trying to learn how to use Hystrix. I've created this class below:
public class CommandReturnAllExceptFive extends HystrixCommand<Integer> {
public static final Integer SLEEP_TIME = 5000;
private Integer x;
public CommandReturnAllExceptFive(Integer x) {
super(getHystrixConfiguration());
this.x = x;
System.out.println("Is circuit breaker open? " + (this.circuitBreaker.isOpen() ? "yes" : "no"));
System.out.println("Requests so far: "+(this.metrics.getRollingCount(HystrixEventType.FAILURE)));
}
public void setX(Integer x) {
this.x = x;
}
private static HystrixCommand.Setter getHystrixConfiguration() {
HystrixCommandProperties.Setter properties
= HystrixCommandProperties.Setter()
.withCircuitBreakerSleepWindowInMilliseconds(SLEEP_TIME)
.withCircuitBreakerEnabled(true)
.withCircuitBreakerRequestVolumeThreshold(1)
.withCircuitBreakerErrorThresholdPercentage(1)
.withMetricsRollingStatisticalWindowBuckets(1)
.withMetricsRollingStatisticalWindowBuckets(1);
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("ReturnAllExceptFive");
return HystrixCommand.Setter.withGroupKey(groupKey).andCommandPropertiesDefaults(properties);
}
protected Integer run() throws Exception {
if (x == 5) {
throw new Exception();
}
return x;
}
}
with the following unit test:
#Test
public void testCommandReturnAllExceptFive_doesStallBeforeCallingAgain() {
boolean exceptionIsThrown = false;
try {
CommandReturnAllExceptFive returnAllExceptFive = new CommandReturnAllExceptFive(5);
returnAllExceptFive.execute();
} catch (Exception ex) {
exceptionIsThrown = true;
}
assertThat(exceptionIsThrown, is(true));
long timeNow = System.currentTimeMillis();
boolean callIsSuccessful = false;
while (!callIsSuccessful) {
try {
CommandReturnAllExceptFive returnAllExceptFive = new CommandReturnAllExceptFive(1);
returnAllExceptFive.execute();
callIsSuccessful = true;
} catch (Exception ex) {
}
}
long timeAfter = System.currentTimeMillis();
long timeToSuccess = timeAfter - timeNow;
System.out.println("timeNow: "+timeNow+"\ntimeAfter: "+timeAfter);
//assertThat(timeToSuccess >= CommandReturnAllExceptFive.SLEEP_TIME, is(true));
}
which is basically verifying that the call fails at 5, and that it does stall for the specified period of time after a successful execution. The debugging statements indicate that the circuit is never closed, but it should be closed after the first call since that one throws an exception, hence indicating failure. Can anyone help me out here?
public class SOQuestion {
private class TaskResult1 {//some pojo
}
private class TaskResult2{// some other pojo
}
private class Task1 implements Callable<TaskResult1> {
public TaskResult1 call() throws InterruptedException {
// do something...
return new TaskResult1();
}
}
private class Task2 implements Callable<TaskResult2> {
public TaskResult2 call() throws InterruptedException {
// do something else...
return new TaskResult2();
}
}
private void cancelFuturesTask1(List<Future<TaskResult1>> futureList ){
for(Future<TaskResult1> future: futureList){
if(future.isDone())
{
continue;
} else
{
System.out.println("cancelling futures.....Task1.");
future.cancel(true);
}
}
}
private void cancelFuturesTask2(List<Future<TaskResult2>> futureList ){
for(Future<TaskResult2> future: futureList){
if(future.isDone())
{
continue;
} else
{
System.out.println("cancelling futures.....Task2.");
future.cancel(true);
}
}
}
void runTasks() {
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletionService<TaskResult1> completionService1 = new ExecutorCompletionService<TaskResult1>(executor);
List<Future<TaskResult1>> futuresList1 = new ArrayList<Future<TaskResult1>>();
for (int i =0 ;i<10; i++) {
futuresList1.add(completionService1.submit(new Task1()));
}
for (int i = 0; i< 10; i++) {
try {
Future<TaskResult1> f = completionService1.take();
System.out.print(f.get());
System.out.println("....Completed..first one.. cancelling all others.");
cancelFuturesTask1(futuresList1);
} catch (InterruptedException e) {
System.out.println("Caught interrruption....");
break;
} catch (CancellationException e) {
System.out.println("Cancellation execution....");
break;
} catch (ExecutionException e) {
System.out.println("Execution exception....");
break;
}
}
CompletionService<TaskResult2> completionService2 = new ExecutorCompletionService<TaskResult2>(executor);
List<Future<TaskResult2>> futuresList2 = new ArrayList<Future<TaskResult2>>();
try{
for (int i =0 ;i<10; i++) {
futuresList2.add(completionService2.submit(new Task2()));
}
for (int i = 0; i< 10; i++) {
try {
Future<TaskResult2> f = completionService2.take();
System.out.print(f.get());
System.out.println("....Completed..first one.. cancelling all others.");
cancelFuturesTask2(futuresList2);
} catch (InterruptedException e) {
System.out.println("Caught interrruption....");
break;
} catch (CancellationException e) {
System.out.println("Cancellation execution....");
break;
} catch (ExecutionException e) {
System.out.println("Execution exception....");
break;
}
}
}catch(Exception e){
}
executor.shutdown();
}
}
As seen in the example, there is some repetition. I want to use Generics and wild card to generalize objects and re-use some methods.
My specific ask would be "cancelFuturesTask1" and "cancelFuturesTask2". Both methods do the same thing. How can I generalize them?
I read this: https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
I created a base class "TaskResult" extended "TaskResult1" and "TaskResult2"
private class TaskResult1 extends TaskResult
private class TaskResult2 extends TaskResult
and then use
List<Futures<? extends TaskResult>>
It gives me complication error and I am having some confusion in extending the concept to List<Futures<?>> in this case.
Any pointers or explanation on how to do that will help here.
Thanks in advance, let me know if you need some clarification.
This compiles fine for me, let me know if you get errors on it also.
public class FutureTest
{
public void cancelAll( Future<?> ... futures ) {
for( Future<?> f : futures ) {
if( !f.isDone() ) {
Logger.getLogger(FutureTest.class.getName()).log(
Level.INFO, "Canceling {0}", f);
f.cancel(true);
}
}
}
public <T extends Task1 & Task2> void cancelAll( List<Future<T>> futures ) {
cancelAll( futures.toArray( new Future[futures.size()]) );
}
}
interface Task1 {}
interface Task2 {}
For a more specific type, see my second method. You can do it with a Generic Method and Bounded Type Parameter, but only if all but one type are interfaces. Java doesn't support multiple inheritance, so you can't write one method that takes multiple (not covariant) class types. That's why I think unbounded (wildcard, "<?>") methods like the first example are better here.
https://docs.oracle.com/javase/tutorial/java/generics/boundedTypeParams.html