AFAIK submitting Callable/Runnable to ExecutorService is the way to go if I want to execute resource-heavy code in parallel. Hence my method structure:
public class ServiceClass {
protected final ExecutorService executorService = Executors.newCachedThreadPool();
public Future<Result> getResult(Object params) {
if (params == null) {
return null; // In situations like this the method should fail
}
// Do other fast pre-processing stuff
return executorService.submit(new CallProcessResult(params));
}
private class CallProcessResult implements Callable<Result> {
private Object params;
public CallProcessResult(Object params) {
this.params = params;
}
#Override
public Result call() throws Exception {
// Compute result for given params
// Failure may happen here too!
return result;
}
}
}
public class Result {
...
}
I have marked 2 spots in the code above in which failures can happen. The options available for error handling are quite different for those 2 cases.
Before submitting the task there can be issues like invalid parameters, some fast pre-processing code that may fail.
I see several ways to signify failure here:
In case of invalid params supplied to getResult return null immediately. In this case I'll have to check if getResult returned null every time I call it.
Throw checked exceptions instead of the above.
Instantiate a Future<Result> that returns null on get() request. I would do that with Apache Commons ConcurrentUtils.constantFuture(null). In this case I would expect getResult to always return some non-null Future<Result>. I like this option more, because it is consistent with the second case.
During task execution I can expect serious errors like lack of memory, corrupted files, unavailable files etc.
I suppose the better option in my case is to return null, because the result of the task is an object.
Also, I could throw checked exceptions and handle them in ThreadPoolExecutor.afterExecute (as suggested by NiranjanBhat). See Handling exceptions from Java ExecutorService tasks
Which is the better practice (in both cases)?
Perhaps there is a different way to do this or a design pattern I should use?
I would suggest that for failure during task processing, you simply throw an appropriate exception. Don't add any special handling for this in the executor. What will happen is that it will be captured, and stored in the Future. When the Future's get method is called, it will throw an ExecutionException, which the caller of get can then unpack and handle. This is essentially how normal exception handling is transposed into the Callable/Future paradigm. This looks like this:
Future<Result> futureResult = serviceClass.getResult("foo");
try {
Result result = futureResult.get();
// do something with result
}
catch (ExecutionException ee) {
Throwable e = ee.getCause();
// do something with e
}
Given that the caller of get has to have this handling of ExecutionExceptions, you could then take advantage of that to deal with failure during submission. To do this, you could construct a Future that is like Apache Commons's constantFuture, but which throws a given exception rather than returns a given value. I don't think there's anything like that in the JDK, but it's simple (if tedious) to write:
public class FailedFuture<T> implements Future<T> {
private final Throwable exception;
public FailedFuture(Throwable exception) {
this.exception = exception;
}
#Override
public T get() throws ExecutionException {
throw new ExecutionException(exception);
}
#Override
public T get(long timeout, TimeUnit unit) throws ExecutionException {
return get();
}
#Override public boolean cancel(boolean mayInterruptIfRunning) { return false; }
#Override public boolean isCancelled() { return false; }
#Override public boolean isDone() { return true; }
}
This is somewhat dodgy - you're taking a failure during a synchronously-called method, and making it look like a failure during the asynchronously-called method. You're shifting the burden of handling the error from the code that actually caused it to some code that runs later. Still, it does mean you can have all the failure handling code in one place; that might be enough of an advantage to make this worthwhile.
You can use afterExecute method. This is defined in the ThreadPoolExecutor, which you will need to override.
This method is called after the execution of each task is completed. You will get the task instance in this callback method. You can record the errors in some variable in your task and access it in this method.
Related
I'm trying to get into CompletableFuture class for a project I'm running, and I got to some question here:
There is the following method: it tries to find a conversation by its ID or hash; and, if not found, it throws an exception. So far, so good.
public ConversationOutput getConversationByIdOrHash(String conversationIdOrHash)
throws ConversationNotFoundException {
Conversation conversation = this.conversationRepository.getByIdOrHash(conversationIdOrHash);
if (conversation == null) {
throw new ConversationNotFoundException(conversationIdOrHash);
}
return this.modelMapper.map(conversation, ConversationOutput.class);
}
Note that I am throwing ConversationNotFoundException from my method signature. My SpringBoot controller is reacting to this exception and it's all working fine since the beginning.
What I'm trying to do is to make this to a CompletableFuture return and actually throwing an exception, something similar to:
public CompletableFuture<ConversationOutput> getConversationByIdOrHashAsync(String conversationIdOrHash)
throws ConversationNotFoundException {
return CompletableFuture.supplyAsync(() -> this.getConversationByIdOrHash(conversationIdOrHash));
}
I've seen posts where people use exceptionally to handle exceptions, but what I really want to do is to throw it to my controller and let it handle it. Any suggestions of how can I make it?
Thank you all!
The question is do you care about the result of CompletableFuture.
CompletableFuture is like a special task and it is processed on other thread. If you don't invoke .join() you won't receive the results of CompletableFuture. This method also will propagate the exception if any occured. However it waits for CompletableFuture to finish and blocks the request.
However, there is no way to get exceptions from the inside of the CompletableFuture without waiting, you have to treat it like other task.
You can pass the completed future in case of a success, and failed future along with your custom exception.
public CompletableFuture<ConversationOutput> getConversationByIdOrHashAsync(String conversationIdOrHash) {
try {
return CompletableFuture.completedFuture(this.getConversationByIdOrHash(conversationIdOrHash));
} catch (ConversationNotFoundException e) {
return CompletableFuture.failedFuture(e);
}
}
and then at your controller level you can handle the exception.
final CompletableFuture<ConversationOutput> future = getConversationByIdOrHashAsync("idOrHash");
future.whenComplete((r, e) -> {
if (e != null) {
if (e instanceof ConversationNotFoundException) {
//handling
}
}
});
I'm working on a project that involves Hystrix, and I decided to use RxJava. Now, forget Hystrix for the rest of this because I believe the main problem is with my complete screwing up of writing the Observable code correctly.
Need:
I need a way to return an observable that represents a number of observables, each running a user task. I want that Observable to be able to return all results from the tasks, even errors.
Problem:
Observable streams die on errors. If I have three tasks and the second task throws an exception, I never receive the third task even if it would have succeeded.
My Code:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return Observable
.from(tasks)
.flatMap(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task).toObservable().subscribeOn(this.schedulerFactory.get(groupName));
} catch(Exception ex) {
return Observable.error(ex);
}
});
}
Given that MyCommand is a class that extends HystrixObservableCommand, it returns an Observable and so shouldn't figure in on the problems I'm seeing.
Attempt 1:
Used Observable.flatMap as above
Good: Each Command is scheduled on it's own thread and the tasks run asynchronously.
Bad: On first Command exception, Observable completes having emitted previous successful results and emitting the Exception. Any in-flight Commands are ignored.
Attempt 2:
Used Observable.concatMapDelayError instead of flatMap
Bad: For some reason, tasks run synchronously. Why??
Good: I get all the successful results.
~Good: OnError gets a Composite exception with a list of the exceptions thrown.
Any help will be greatly appreciated and probably result in me being very embarrassed for not having thought of it myself.
Additional Code
This test succeeds with Observable.flatMap, but fails when using Observable.concatMapDelayError because the tasks do not run asynchronously:
java.lang.AssertionError: Execution time ran over the 350ms limit: 608
#Test
public void shouldRunManagedAsyncTasksConcurrently() throws Exception {
Observable<String> testObserver = executor.observeManagedAsync("asyncThreadPool",getTimedTasks());
TestSubscriber<String> testSubscriber = new TestSubscriber<>();
long startTime = System.currentTimeMillis();
testObserver.doOnError(throwable -> {
System.out.println("error: " + throwable.getMessage());
}).subscribe(testSubscriber);
System.out.println("Test execution time: "+(System.currentTimeMillis()-startTime));
testSubscriber.awaitTerminalEvent();
long execTime = (System.currentTimeMillis()-startTime);
System.out.println("Test execution time: "+execTime);
testSubscriber.assertCompleted();
System.out.println("Errors: "+testSubscriber.getOnErrorEvents());
System.out.println("Results: "+testSubscriber.getOnNextEvents());
testSubscriber.assertNoErrors();
assertTrue("Execution time ran under the 300ms limit: "+execTime,execTime>=300);
assertTrue("Execution time ran over the 350ms limit: "+execTime,execTime<=350);
testSubscriber.assertValueCount(3);
assertThat(testSubscriber.getOnNextEvents(),containsInAnyOrder("hello","wait","world"));
verify(this.mockSchedulerFactory, times(3)).get("asyncThreadPool");
}
Tasks for the above unit test:
protected List<EspTask<String>> getTimedTasks() {
EspTask longTask = new EspTask("helloTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(100);
return "hello";
}
};
EspTask longerTask = new EspTask("waitTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(150);
return "wait";
}
};
EspTask longestTask = new EspTask("worldTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(300);
return "world";
}
};
return Arrays.asList(longTask, longerTask, longestTask);
}
You can use Observable.onErrorReturn(), and return special value (e.g. null), then filter non-special values downstream. Keep in mind that source observable will complete on error. Also depending on use case Observable.onErrorResumeNext()methods can be useful aswell. If you are interested in error notifications, use Observable.materialize(), this will convert items and onError(), onComplete() into Notifications, which then can be filtered by Notification.getKind()
Edit.
All operators mentioned above should be added right after .toObservable().subscribeOn(this.schedulerFactory.get(groupName)); assuming try/catch was absent.
You want to use mergeDelayError:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return Observable.mergeDelayError(Observable
.from(tasks)
.map(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task).toObservable().subscribeOn(this.schedulerFactory.get(groupName));
} catch(Exception ex) {
return Observable.error(ex);
}
}));
}
Note that your MyCommand constructor should not throw any exceptions; this allows your code to be written more concisely:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return from(tasks)
.map(task -> new MyCommand(task.getTaskId(), groupName, task)
.toObservable()
.subscribeOn(this.schedulerFactory.get(groupName)))
.compose(Observable::mergeDelayError);
}
Keep in mind that this will still invoke onError at most once; if you need explicit handling of all errors, use something like an Either<CommandResult, Throwable> as the return type (or handle the errors and return an empty observable).
Use .materialize() to allow all emissions and errors to come through as wrapped notifications then deal with them as you wish:
.flatMap(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task)
.toObservable()
.subscribeOn(this.schedulerFactory.get(groupName))
.materialize();
} catch(Exception ex) {
return Observable.error(ex).materialize();
}
});
Say you have some long running task wrapped by an observable:
Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
return longRunningTask();
}
}
Is there any way to check whether the observable has been unsubscribed to determine if we should cancel the work and bail out?
More specifically, is it possible to check the status of a subscription (e.g. isUnsubscribed()) when using Observable.defer() or Observable.fromCallable()?
I'm aware that you can check subscriber.isUnsubscribed() when using Observable.create(), however, since it's ill-advised to use Observable.create(), how can this be done with other operators?
What about using Observable.doOnSubscribe(Action0) and Observable.doOnUnsubscribe(Action0). You can count the subscriptions and when there are none you can stop the job.
Greetings,
Martin
The fromCallable doesn't expose the consumer. For this, you need create with a body such as the following:
final SingleDelayedProducer<T> singleDelayedProducer =
new SingleDelayedProducer<T>(subscriber);
subscriber.setProducer(singleDelayedProducer);
try {
T result;
// computation
if (subscriber.isUnsubscribed()) {
return;
}
// more computation
result = ...
singleDelayedProducer.setValue(result);
} catch (Throwable t) {
Exceptions.throwOrReport(t, subscriber);
}
Based on the examples of guava I've seen I've been looking for elegant solutions to my problem. Specifically, I like the way Futures.addCallback(ListenableFuture, FutureCallback) works, but I'd like to be able to set a timeout on the length of time that can expire before the FutureCallback is invoked. Optimally It would be nice if breaching the timeout just caused an the failure condition of FutureCallback to be called.
Does Guava have something like this already? Is it just not recommended to try to couple timeouts with the callbacks?
EDIT: Including example of the code that led me to this point. Obviously, I stripped out the meaningful bits to get a minimum example.
#Test
public void testFuture()
{
Callable<Boolean> callable = new Callable<Boolean>()
{
#Override
public Boolean call() throws Exception
{
while(true);
}
};
ListenableFuture<Boolean> callableFuture = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()).submit(callable);
Futures.addCallback(callableFuture, new FutureCallback<Boolean>()
{
#Override
public void onFailure(Throwable arg0)
{
System.out.println("onFailure:"+arg0);
}
#Override
public void onSuccess(Boolean arg0)
{
System.out.println("onSuccess:"+arg0);
}
});
try
{
callableFuture.get(1000, TimeUnit.MILLISECONDS);
}catch(Throwable t)
{
System.out.println("catch:"+t);
}
}
This code will only print catch:java.util.concurrent.TimeoutException.
Update: This has been added to Guava as Futures.withTimeout().
Internally, we have a makeTimeoutFuture method that takes a Future as input and returns a new Future that will have the same result unless the original hasn't completed by a given deadline. If the deadline expires, the output Future has its result set to a TimeoutException. So, you could call makeTimeoutFuture and attach listeners to the output Future.
makeTimeoutFuture isn't the most natural solution for your problem. In fact, I think that the method was created primarily to set a hard timeout on no-arg get() calls, since it can be a pain to propagate the desired deadline to all callers. A more natural solution is to reason that get() is to get(long, TimeUnit) as addCallback(ListenableFuture, FutureCallback) is to addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService). That's a little clumsy, albeit less so than makeTimeoutFuture. I'd want to give this more thought before committing to anything. Would you file a feature request?
(Here's what we have internally:)
public static <V> ListenableFuture<V> makeTimeoutFuture(
ListenableFuture<V> delegate,
Duration duration,
ScheduledExecutorService scheduledExecutor)
Returns a future that delegates to another but will finish early (via a TimeoutException wrapped in an ExecutionException) if the specified duration expires. The delegate future is not cancelled in this case.
scheduledExecutor.schedule(new Runnable() {
#Override public void run() {
TimeoutFuture.this.setException(new TimeoutException("Future timed out"));
}
}, duration.getMillis(), TimeUnit.MILLISECONDS);
We are working on a project to handle virtual machine managers from a Java application.
At the moment, we faced a problem where some instructions must be considered as a task because they require more time. Theses taks can also end with errors or be a success, and we can't know the result from the application unless we request the state of the task to the VM hypervisor.
To have a smooth application we wanted to have a CommandManager to handle the differents request to theses hypervisors in separated threads. The problem is that these Command might return specific errors such as that we used to catch in the view to display revelant information to the user but when we implement Runnableon our Commands interface, we can't throw any exception out of that thread back to reach the view.
What could I do to keep notifying the user of the errors that happened and their nature?
Sorry for my english!
Lets see the code below for a brief example :
First the Command
class ChangeMemorySize extends Command {
private String name;
private int memorySizeMb;
public ChangeMemorySize(Hypervisor hypervisor, String server,
String name, int memory) {
super(hypervisor, server);
this.name = name;
this.memorySizeMb = memory;
}
protected void execute() throws ConnectionException,OperationException{
//Some code here
}
public void run() //CANT THROW ANYTHING HERE :throws VmConfigFault,
try{
execute();
}catch{Exception e){
// I have to catch it all here!
}
This isn't real code this is just an example. This command would then be passed to a manager who would run it in another thread. But I loose all the specifics exception that I used to notify the user of what really happened in there!
Use an ExecutorService and do one of two things.
First you can store all results in a Future and when you want to know if an Exception occurs just invoke Future.get() and handle any exception.
Second you can create the ExecutorService with a ThreadFactory in which you set it a knew UncaughtExceptionHandler like
final UncaughtExceptionHandler handler = new UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
// notify error
}
});
Executor executor = Executors.newFixedThreadPool(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setUncaughtExceptionHandler(handler);
return thread;
}
});
While I agree with #John Vint that ExecutorService with an UncaughtExceptionHandler is a good approach, if for some reason you really want to stick with Runnables, I'd suggest that your base class, Command, have some fields/getters for status and Exception. e.g.
Enum Status {FAILED, CANCELLED, SUCCESS};
// protected so subclasses can set them
protected Status status;
protected Exception exception; // null means none
public Status getStatus();
public Exception getException();
You might even want to add a result field to really mimic a Callable.
For simplicity, then add a method that subclasses can call in the catch clause
protected void s***Happenned(Exception e) {
this.exception = e;
status = FAILED;
// any standard cleanup can go here too...
}