I'm creating an API that provides resources to the client which they will need to explicitly release (a la Closeable.close()) vi a Future. This pattern has a lot of nice features for our use case, but it comes with one wrinkle. If the client decides they no longer need the resource they can call Future.cancel(true) to cancel the (potentially expensive) allocation. However this introduces a race condition; if the resource finishes allocating before .cancel() is actually called then the future won’t actually free the resource.
Here’s an example:
Future<Resource> resource = service.requestResource();
try {
doSomething(resource.get(1, TimeUnit.MINUTES));
} catch (TimeoutException e) {
// by this point resource could be done, and .cancel() will be a no-op
resource.cancel(true);
}
It seems the "right" thing to do is for clients to always attempt to release the resource after calling cancel, e.g.:
if (!resource.cancel(true)) {
resource.get().close();
}
But this seems easy for a client to misuse. One option would be to use a ForwardingFuture and decorate .cancel() with this close-if-done behavior, but that seems like it would violate the contract that .cancel() "will fail if the task has already completed".
Must Future.cancel() no-op if the task is done? Is there a better pattern that resolves this race condition in a less error-prone manner? Or is this just something Future isn't designed to handle, and we should avoid using it?
Assuming you can expect your clients to at least call cancel just make it do the right thing by implementing it yourself:
public class CloseableFuture<V extends Closeable> extends FutureTask<V> {
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (!super.cancel(true)) {
// Handle exception
get().close();
return false;
}
else {
return true;
}
}
}
Related
I have been going over the realm documentation and found no feasible way of cancelling an asynchronous transaction from within the transaction "body" i.e. Realm.Transaction.execute()
So the only recourse I seem to have if I want to use the executeTransactionAsync() API's is to do something like:
realm.executeTransactionAsync(
new Realm.Transaction() {
#Override
public void execute(#NonNull Realm realm) {
// pretend we have some inter dependent database operations here
if (failureCondition) {
throw new Error("Failed transaction");
}
// and more here...
}
},
new Realm.Transaction.OnError() {
#Override
public void onError(#NonNull Throwable error) {
Log.e(LOG_TAG, error.getMessage());
}
}
);
Is there really no better way to do this? If re-ordering the operations such that a simple return would suffice and the transaction could be partially committed was an option that is obviously what I would do but what if it isn't.
Of course the above is technically functionally identical to just calling realm.cancelTransaction() in execute(), since it causes the attempt to commit the transaction that no-longer exists to throw an exception anyways. However, judging from the fact that the actual async transaction code behind this nice API doesn't check with realm.isInTransaction() before attempting to commit nor allows execute() to throw any checked exceptions neither approach seems to be something the designers even considered a valid use case.
I guess in the end I sort of answered myself, so perhaps the better question would be... is this a problem with the design of the API itself or am I just attempting to do something fundamentally wrong.
I read google docs, but there is said about non deferred task only. There we create xml file with params and can specify retry count.
But I use deferred tasks:
public static class ExpensiveOperation implements DeferredTask
{
#Override
public void run()
{
System.out.println("Doing an expensive operation...");
// expensive operation to be backgrounded goes here
}
}
and create it that way:
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withPayload(new ExpensiveOperation(/*different params*/)));
How to specify that I don't want it to be restarted in case of failure?
I'm not a Java user, but I see this in Interface DeferredTask which I think you may be able to use:
Normal return from this method is considered success and will not
retry unless DeferredTaskContext.markForRetry() is called.
Exceptions thrown from this method will indicate a failure and will be
processed as a retry attempt unless
DeferredTaskContext.setDoNotRetry(boolean) was set to true.
I have a webapp in which I have to return the results from a mongodb find() to the front-end from my java back-end.
I am using the Async Java driver, and the only way I think I have to return the results from mongo is something like this:
public String getDocuments(){
...
collection.find(query).map(Document::toJson)
.into(new HashSet<String>(), new SingleResultCallback<HashSet<String>>() {
#Override
public void onResult(HashSet<String> strings, Throwable throwable) {
// here I have to get all the Json Documents in the set,
// make a whole json string and wake the main thread
}
});
// here I have to put the main thread to wait until I get the data in
// the onResult() method so I can return the string back to the front-end
...
return jsonString;
}
Is this assumption right or there´s another way to do it?
Asynchronous APIs (any API based on callbacks, not necessarily MongoDB) can be a true blessing for multithreaded applications. But to really benefit from them, you need to design your whole application architecture in an asynchronous fashion. This is not always feasible, especially when it is supposed to fit into a given framework which isn't built on callbacks.
So sometimes (like in your case) you just want to use an asynchronous API in a synchronous fashion. In that case, you can use the class CompletableFuture.
This class provides (among others) two methods <T> get() and complete(<T> value). The method get will block until complete is called to provide the return value (should complete get called before get, get returns immediately with the provided value).
public String getDocuments(){
...
CompletableFuture<String> result = new CompletableFuture<>(); // <-- create an empty, uncompleted Future
collection.find(query).map(Document::toJson)
.into(new HashSet<String>(), new SingleResultCallback<HashSet<String>>() {
#Override
public void onResult(HashSet<String> strings, Throwable throwable) {
// here I have to get all the Json Documents in the set and
// make a whole json string
result.complete(wholeJsonString); // <--resolves the future
}
});
return result.get(); // <-- blocks until result.complete is called
}
The the get()-method of CompletableFuture also has an alternative overload with a timeout parameter. I recommend using this to prevent your program from accumulating hanging threads when the callback is not called for whatever reason. It will also be a good idea to implement your whole callback in a try { block and do the result.complete in the finally { block to make sure the result always gets resolved, even when there is an unexpected error during your callback.
Yes, you're right.
That's the correct behaviour of Mongo async driver (see MongoIterable.into).
However, Why don't you use sync driver in this situation? Is there any reason to use async method?
I have a layered architecture in a Java web application. The UI layer is just Java, services are typed Akka actors and external service calls (WS, DB etc.) are wrapped in Hystrix commands.
THe UI calls the service and the service returns an Akka future. It's an Akka future because I want to make UI coding simpler with the onComplete and onFailure callbacks that Akka futures provide. The service then creates the future that does some mapping etc. and wraps a call to a HystrixCommand that returns a Java future.
So in pseudocode:
UI
AkkaFuture future = service.getSomeData();
Service
public AkkaFuture getSomeData() {
return future {
JavaFuture future = new HystrixCommand(mapSomeData()).queue()
//what to do here, currently just return future.get()
}
}
The problem is that I would like to free up the thread the service actor is using and just tie up the threads that Hystrix uses. But the java future prevents that because I have to block on it's completion. The only option I can think of (which I'm not sure I like) is to poll the Java future(s) constantly and complete the Akka future when the Java future finishes.
Note: the question isn't really related to Hystrix per se, but I decided to mention it if somebody comes up with a solution specifically related to Hystrix.
I'm marking the answer by #Hbf as a solution, since I ended up doing an Akka poller as explained in How do I wrap a java.util.concurrent.Future in an Akka Future?. For reference I also tried:
Creating a HystrixCommandExcutionHook and extending HystrixCommand to allow callbacks. That didn't work because the hook wasn't called at the right time.
Using Guavas listenable future by having a decorated executor create the futures inside Hystrix and then casting the futures from the commands. Doesn't work because Hystrix uses a ThreadPoolExecutor which can't be decorated.
EDIT: I'm adding the Akka poller code below, since the original answer was in Scala and it hangs if the Java future doesn't cancel nicely. The solution below always walks away from threads after a timeout.
protected Future wrapJavaFutureInAkkaFuture(final java.util.concurrent.Future javaFuture, final Option maybeTimeout, final ActorSystem actorSystem) {
final Promise promise = Futures.promise();
if (maybeTimeout.isDefined()) {
pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, Option.option(maybeTimeout.get().fromNow()), actorSystem);
} else {
pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, Option. none(), actorSystem);
}
return promise.future();
}
protected void pollJavaFutureUntilDoneOrCancelled(final java.util.concurrent.Future javaFuture, final Promise promise, final Option maybeTimeout, final ActorSystem actorSystem) {
if (maybeTimeout.isDefined() && maybeTimeout.get().isOverdue()) {
// on timeouts, try to cancel the Java future and simply walk away
javaFuture.cancel(true);
promise.failure(new ExecutionException(new TimeoutException("Future timed out after " + maybeTimeout.get())));
} else if (javaFuture.isDone()) {
try {
promise.success(javaFuture.get());
} catch (final Exception e) {
promise.failure(e);
}
} else {
actorSystem.scheduler().scheduleOnce(Duration.create(50, TimeUnit.MILLISECONDS), new Runnable() {
#Override
public void run() {
pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, maybeTimeout, actorSystem);
}
}, actorSystem.dispatcher());
}
}
Java futures are known to be inferior in design compared to something like Scala futures. Take a look at the discussion "How do I wrap a java.util.concurrent.Future in an Akka Future", for example.
But: Maybe, instead of polling (as suggested in the above discussion), Hystrix offers some kind of onComplete callback? I do not know the library at all but stumbled upon an onComplete in the Hystrix API. Maybe it helps?
As of Hystrix 1.3 it now also supports true non-blocking callbacks and that will fit much better into Akka/Scala Future behavior that is non-blocking and composable: https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Reactive-Execution
In Java, I've gotten used to working with Futures. Now I'm looking at Android, and AsyncTask implements almost all the same methods and covers similar lifecycles. But, if I want to be consistent and use Future all over my code, I have to wrap AsyncTask in a stupid wrapper, cause it doesn't actually implement Future.
All they'd need to add is an isDone() method, which seems like it would be trivial, then add implements Future<Result>. (added later: see my answer below for just how trivial it would be).
Any Android experts know some good reason / obscure bug it might cause why this hasn't been done?
From reading the actual code of AsyncTask.java it actually uses a Future task and then some more. A Future is a task that executes asynchronously on the go. An AsyncTask is scheduled on a queue for a single (or pool of) background thread(s).
An AsyncTask is actually more "superior" than a Future task. It does fancy scheduling and optimizations on top of Future's functionality. Just look at the API introduction levels. Future was introduced right from the start API 1.0. The AsyncTask object was introduced in API 3.
An AsyncTask has-a Future task, not is-a Future.
AsyncTask.java
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
#Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
I'm still interested in the theoretical reasons "why" not to use AsyncTask for a Future.
But, for the record, I ended up creating my own little class (shown below). Just extend it instead of AsyncTask if you want a Future. IMO, a cleaner way than the #Eng.Fouad idea of accessing the private mFuture within the code. (But thanks for the idea, it got me looking into the source code a bit!) YMMV.
public abstract class FutureAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> implements Future<Result>{
#Override
public boolean isDone() {
return AsyncTask.Status.FINISHED == getStatus();
}
}
AsyncTask is too simple. It's intended for short tasks which may take a few seconds, but for which you don't want to lock up the UI thread. If you actually need a Future, your task is probably too complex for an AsyncTask anyway.
You can check the status of an AsyncTask by calling getStatus(). This will return an enum which can be one of Status.PENDING, Status.RUNNING or Status.FINISHED.