Re-execute Callable if it fails - java

Having an ExecutorService that executes a Callable that is supposed to be always running, what is the best implementation to relaunch it when an error happens?
Currently my source code looks something like this:
Future<Void> future = executorService.submit(new AlwaysOnlineCallable(config));
try {
future.get();
} catch (Exception e) {
//TODO thinking on execcuting the callable here
e.printStackTrace();
}
For what I've seen, cases like this are generally treated with runables.

Why not simply:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit((Runnable) () -> {
while (true) {
try {
...
} catch (Exception e) {
// log
}
}
});
There doesn't seem to be any need for a Callable or a Future.

Related

Non interrupted code running via Executor Service

Im familiar with the fact that we as developers need to add a check for interrupts in our code when we write something that might run async via threads.
The following example shows the wrong case, when there is no check for interrupt in the runnable and therefore even if I got timeout exception on the main thread, the child thread keep running the task :
public void myTest() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Void> future = executorService.submit(() -> {
while (true) {
log.info("test");
Thread.sleep(40);
}
});
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
Thread.sleep(500);
log.info("done");
output :
test
test
test
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at myFile.myTest(MyFile.java:102)
test
test
test
test
done
By adding future.cancel(true) I got an unexpected behavior. According to what I understood, the cancel(boolean) method wont stop the task, if the task is already running, it might only interrupt it and thats all.
The code :
public void myTest() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Void> future = executorService.submit(() -> {
while (true) {
log.info("test");
Thread.sleep(40);
}
});
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
boolean value = future.cancel(true);
log.info(""+value);
}
Thread.sleep(500);
log.info("done");
The output :
test
test
test
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at myFile.myTest(MyFile.java:102)
true
done
So why by adding the future.cancel(true) the runnable stopped running ? I expected that during the 500 mili seconds that the main thread sleeps, I will see more test prints like I saw in the previous example.
When you call future.cancel(true), it will try to interrupt your executor thread. Executor thread will receive InterruptedException and die. That's where your FutureTask stops executing.

Exception in a runnable appears to kill threadpool

I have a runnable that I want to run periodically. On a particular run, I believe the runnable encountered a null pointer, but no exception was shown on the console. After that failed run, it never runs again. I have two questions:
If there was a null pointer, why wasn't this shown on the console
How can I have the scheduled task run again in the future, even if a particular run fails?
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);
Answering your questions,
1) The reason why you do not see any kind of exception is due to the fact that the FutureTask#setException called within FutureTask#run effectively swallows it. In order to be be able to log the exception you should either create a new class the extends the ScheduledThreadPoolExecutor and override the afterExecute method like so:
#Override
protected void afterExecute(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
t = e;
}
}
if (t != null) {
t.printStackTrace();
}
}
Or directly invoke get on the returned ScheduledFuture like so:
var executor = Executors.newSingleThreadScheduledExecutor();
var future = executor.scheduleAtFixedRate(new MyRunnable(null), 1, 1, TimeUnit.SECONDS);
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
2) The easiest way of re-running the failed runnable would to do this:
while (true) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
But imho this approach is not the cleanest. Properly coding your Runnable#run method to handle exception would be a better solution.

Running a thread for some fixed time and killing it if time is out

I want to run a thread for some fixed amount of time.
If it is not completed within that time, I want to either kill it, throw some exception, or handle it in some way. How can this be done?
You should use an ExecutorService:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new Task());
try {
System.out.println("Started");
Integer retval = future.get(10, TimeUnit.SECONDS)); // you can choose your desired time here
System.out.println("Finished");
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("Timeout happened");
// handle termination here
}
executor.shutdownNow();
And your Callable can look something like this:
class Task implements Callable<Integer> {
#Override
public String call() throws Exception {
// some code here
return 0;
}
}

TimeoutTask using ExecutorService

I have implmented a TimeoutTask using ExecutorService. In the below method I am submitting the TimeoutTask and if it is timed out in a given time, I cancel the task and shuts down the executor.
private boolean waitForProcessToBeCompleted(long timeOut) {
boolean result = false;
ExecutorService executor = Executors.newSingleThreadExecutor();
// Create a FutureTask which will be run
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new TimeoutTask());
executor.submit(futureTask); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
}
It is running very well and I don't have any issue.
However, I would like to know whether this is the best code design. I was just wondering if it could have been better to use a Future returned by ExecutorService.submit() to get the return value of the Callable or to time out the TimeoutTask. e.g.
Future<?> futureTask = executor.submit(new TimeoutTask()); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
I am using JDK7.
I would prefer using CountDownLatch:
List<List<String>> elements = MyPartition.partition(bigObjectList, size);
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newSingleThreadExecutor();
CountDownLatch doneSignal = new CountDownLatch(10);
for(List<String> l: elements) {
ReadTask worker = new ReadTask(doneSignal, l);
tasks.add(executor.submit(worker));
}
long timeout = 10000;
doneSignal.await(timeout, TimeUnit.SECONDS);
boolean notFinished = false;
if(doneSignal.getCount() > 0) {
for(Future<?> fut : tasks) {
if(!fut.isDone()) {
System.out.println("Sub Thread " + fut + " has not finshed!");
fut.cancel(true);
notFinished = true;
}
}
}
If you look at the code of futureTask.cancel, you'll see that it just attempts to interrupt the thread which is executing the task. This interruption may work if the task regullary checks the interruption flag, explicitly or implicitly (via calling to sleep() or wait()). In Java, there is no other safe way to stop execution of a method.
So, you can implement the same functionality without creating each time a separate single-threaded executor. Instead, execute the TimerTask from within the waitForProcessToBeCompleted method. In order to be notified of timeout, submit a watching task to a SheduledExecutorService. The watching task should interrupt the thread which executes the TimerTask. If the task is completed before timeout, cancel the watching task.
This way you need a SheduledExecutorService, but it consumes very little processor cycles, and can be reused all over the application.
The invokeAll method on ExecutorService can be used to automatically cancel tasks that exceed the timeout. This lets you cancel tasks without shutting down the threadpool (which let's you re-use the same threadpool for other things if you choose).
private boolean waitForProcessToBeCompleted(long timeOut) {
ExecutorService executor = Executors.newSingleThreadExecutor();
List<FutureTask> tasks = new ArrayList<>();
tasks.add(new SomeFutureTaskThing()));
List<Future<Boolean>> results;
try {
results = executor.invokeAll(tasks, timeOut, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupt status.
return null;
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
}
Future<Boolean> result = results.get(0);
try {
return result.get();
} catch (CancellationException e) {
System.err.println("Timed out");
return null;
}
}

How to properly multi-thread a collection of independent tasks?

I'm using this code to divide up a few hundred tasks between different CPU cores.
final List<Throwable> errors = Collections.synchronizedList(Lists.<Throwable>newArrayList());
final ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (...) {
pool.execute(new Runnable() { #Override public void run() {
try {
// TASK HERE
} catch (Throwable e) {
errors.add(e);
}
}});
}
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!errors.isEmpty()) throw Exceptions.wrap(errors.get(0)); // TODO multi-exception
It works, but it's not nice.
There is no version of awaitTermination without timeout, which is what I want.
I need to do my own error collecting.
What is the proper/common way to do this?
The point of a thread pool is to reuse threads. You should create it on application startup, outside of your code that creates tasks, and inject it. There is no need to shut down the pool after adding tasks. You do that when your application is shutting down.
To run a collection of tasks, use ExecutorService.invokeAll. To get the results afterwards, call get on each of the returned Futures. It will rethrow any exception that the task threw, so you can collect it afterwards.
You can use a future to do the error handling:
final List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < 5; i++) {
futures.add(pool.submit(new Runnable() { #Override public void run() {
// TASK HERE
}}));
}
for (Future f : futures) {
try {
f.get();
} catch (ExecutionException e) {
//something bad happened in your runnable
}
}
//when you are done with the executor
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
I think you need to submit each Runnable, get a Future back, and then call get() on each Future.
When you call get(), you'll either get the result of the Runnable, or the exception that it encountered.

Categories

Resources