The following example is taken from Spring' Getting Started Creating Asynchronous Methods.
#Service
public class GitHubLookupService {
#Async
public CompletableFuture<User> findUser(String user) throws InterruptedException {
logger.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
User results = restTemplate.getForObject(url, User.class);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(1000L);
return CompletableFuture.completedFuture(results);
}
}
AFAIK my knowledge of async methods in computer science goes - It should return immediately. It should be non-blocking.
So lets say somewhere in Spring lets say my code findUser() is called like so:
CompletableFuture<User> user = service.findUser("foo");
This would actually block. It would block a different thread on the Executor service but it would block due to the Thread.sleep(1000L). Correct ?
So how is this async ?
I mean the whole point of CompletableFuture is to get a reference to a computation that will be completed in the future. But here when I get back the completed future the computation is already over, ie. we are using CompletableFuture.completedFuture(results).
So what is the point of having a CompletableFuture in this case ? I mean if I am going to block and return only when my computation is over and I have the results, I might as well just return the result and not the CompletableFuture.
How is this truly non-blocking/async ?
The only non-blocking aspect I find here is offload to a different thread, nothing else.
Am I going wrong somewhere ? What am I missing ?
Thanks.
The problem lies in the way you create your Future. The code you use is
CompletableFuture.completedFuture(results)
Quoting from the JavaDoc, this is only a wrapper between sync and async, where the computation was done synchronously:
Returns a new CompletableFuture that is already completed with the given value.
This is useful in certain situations where you only want to do asynchronous work for some inputs. Consider
(x) -> x==0 ? CompletableFuture.completedFuture(0) : CompletableFuture.supplyAsync(expensiveComputation)
I hope this makes the difference clear - if you want truly async computations, you need to use the supplyAsync function:
Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() with the value obtained by calling the given Supplier.
The detail you're missing is that when #Async is used (and correctly configured), a proxy bean will be used, wrapping your service bean. Any calls to the asynchronous methods through the proxy will use a Spring TaskExecutor to asynchronously run the method.
Wrapping the method response in a synchronous Future such as CompletableFuture.completedFuture is necessary so the return type can be a Future. However, the Future you return is not the one returned by the proxy. Rather, the proxy returns a Future provided by the TaskExecutor, which will be processed asynchronously. The Future you create through e.g. CompletableFuture.completedFuture is unwrapped by the proxy, and its completion result is returned by the proxy's Future.
Proxying documentation
I don't see all of the aforementioned proxying details explicitly stated in either the Spring reference documentation or in the #Async or #EnableAsync Javadocs. However, the details can be pieced together by reading between the lines of what is provided.
The #Async Javadocs mentions the service proxy in passing, and explains why CompletableFuture.completedFuture is used in the service method's implementation:
A Future handle returned from the proxy will be an actual asynchronous Future that can be used to track the result of the asynchronous method execution. However, since the target method needs to implement the same signature, it will have to return a temporary Future handle that just passes a value through: e.g. Spring's AsyncResult, EJB 3.1's AsyncResult, or CompletableFuture.completedFuture(Object).
The fact that proxying is involved is also made apparent by the fact that two of the #EnableAsync annotation elements specify proxying details: mode and proxyTargetClass.
Question example
Finally, applying this to the question example will make it concrete. Code that calls the findUser method on the GitHubLookupService bean will actually be calling a method on a proxy class, rather than directly on the GitHubLookupService instance. The proxy class's findUser method submits a task to Spring's TaskExecutor, and return a CompletableFuture that will asynchronously be completed when the submitted task completes.
The submitted task will call the actual findUser method in the non-proxied GitHubLookupService. This will will perform the REST call, sleep 1 second, and return a completed CompletableFuture with the REST results.
Since this task is happening in a separate thread created by Spring's TaskExecutor, the calling code will continue to proceed past the GitHubLookupService.findUser call immediately, even though it will take at least 1 second for it to return.
If the result of the findUser call is used in the calling code (using e.g. CompletableFuture.get()), the value it will get from that Future will be the same results value passed to CompletableFuture.completedFuture in the GitHubLookupService code.
Related
I still do not understand when to apply this method. In fact, it is similar to Mono.just, but I heard that callback is used for heavy operations if it needs to be performed separately from other flows. Now I use it like this, but is it correct.
Here is an example of use, I wrap sending a firebase notification in a callback since the operation is long
#Override
public Mono<NotificationDto> sendMessageAllDevice(NotificationDto notification) {
return Mono.fromCallable(() -> fcmProvider.sendPublicMessage(notification))
.thenReturn(notification);
}
maybe I still had to wrap up here in Mono.just ?
It depends which thread you want fcmProvider.sendPublicMessage(...) to be run on.
Either the one currently executing sendMessageAllDevice(...):
T result = fcmProvider.sendPublicMessage(notification);
return Mono.just(result);
Or the one(s) the underlying mono relies on:
Callable<T> callable = () -> fcmProvider.sendPublicMessage(notification);
return Mono.fromCallable(callable);
I would guess you need the latter approach.
If you use Mono.just(computeX()), computeX() is called immediately. No want you want(I guess).
If you use Mono.fromCallable(() -> computeX()), the computation is still not performed. I mean computeX() is only called when you subscribe to it. Maybe using .map, .flatMap, etc.
Important: if computeX() return Mono you doe not need to use Mono.fromCallable. It's only for blocking code
As you explained in the description, Mono.fromCallable is used when you want to compute a result with an async execution (mostly some heavy operation).
Since, you have already generated the Mono with Mono.fromCallable you do not have to wrap it again with Mono.just.
I am writing Aspects for methods that return promises. Consider the following method:
public Mono<Stream> publishToKafka(Stream s) {
//publishToKafka is asynchronous
return Mono.just(s).flatMap(worker::publishToKafka);
}
I want to cache if the publish was successful or not. Since this is a cross-cutting concern, an Aspect looks like the best design. Here's my Aspect for it.
#Around("#annotation....")
public Object cache() {
//get the data to cache from the annotation
Object result = pjp.proceed();
cache.cache("key","data");
return result;
}
Now since publishToKafka is asynchronous, the target method returns as soon as the thread switch happens and cache.cache() is called. This is not what I want. What I want is that the result should be cached iff the event was successfully published to Kafka. The following advice works.
#Around("#annotation....")
public <T extends Stream<T>> Mono<T> cache() {
//get the data to cache from the annotation
return ((Mono<T>)pjp.proceed()).doOnNext(a -> cache.cache(key, data));
}
I want to understand what's going on here. Does this happen during the assembly time of the pipeline? Or during the execution time (pjp.proceed() returns a promise) to which my advice adds the doOnNext operator?
I need to understand assembly vs. execution time in the context of this example.
Both Spring AOP and AspectJ aspects are always executed synchronously in the same thread as the intercepted joinpoint. Thus, if your intercepted method returns immediately and the return value is something like a promise, a future or nothing (void) in combination with a callback, you cannot expect to magically get the asynchronous result in the aspect's advice. You do need to make the aspect aware of the asynchronous situation.
Having said that, I also want to mention that I never used reactive programming before, I only know the concept. From what I see in your advice, the solution should work, but one thing is not so nice: You make the advice return a new Mono instance returned by your doOnNext(..) call. Maybe it would be cleaner to return the original Mono you get from proceed() after having registered your caching callback on it, just so as to avoid any side-effects.
I don't know what else to explain, the situation is pretty clear. Feel free to ask directly related follow-up questions if my explanation does not suffice.
I've got a question about CompletableFuture and its possible usage for lazy computations.
It seems like it is a great substitute for RunnableFuture for this task since it is possible to easily create task chains and to have total control of each chain link. Still I found that it is very hard to control when exactly does the computation take place.
If I just create a CompletableFuture with supplyAssync method or something like that, it is OK. It waits patiently for me to call get or join method to compute. But if I try to make an actual chain with whenCompose, handle or any other method, the evaluation starts immediately, which is very frustrating.
Of course, I can always place some blocker task at the start of the chain and release the block when I am ready to begin calculation, but it seems a bit ugly solution. Does anybody know how to control when does CompletableFuture actually run.
CompletableFuture is a push-design, i.e. results are pushed down to dependent tasks as soon as they become available. This also means side-chains that are not in themselves consumed still get executed, which can have side-effects.
What you want is a pull-design where ancestors would only be pulled in as their data is consumed.
This would be a fundamentally different design because side-effects of non-consumed trees would never happen.
Of course with enough contortions CF could be made to do what you want, but you should look into the fork-join framework instead which allows you to only run the computations you depend on instead of pushing down results.
There's a conceptual difference between RunnableFuture and CompletableFuture that you're missing here.
RunnableFuture implementations take a task as input and hold onto it. It runs the task when you call the run method.
A CompletableFuture does not hold onto a task. It only knows about the result of a task. It has three states: complete, incomplete, and completed exceptionally (failed).
CompletableFuture.supplyAsync is a factory method that gives you an incomplete CompletableFuture. It also schedules a task which, when it completes, will pass its result to the CompletableFuture's complete method. In other words, the future that supplyAsync hands you doesn't know anything about the task, and can't control when the task runs.
To use a CompletableFuture in the way you describe, you would need to create a subclass:
public class RunnableCompletableFuture<T> extends CompletableFuture<T> implements RunnableFuture<T> {
private final Callable<T> task;
public RunnableCompletableFuture(Callable<T> task) {
this.task = task;
}
#Override
public void run() {
try {
complete(task.call());
} catch (Exception e) {
completeExceptionally(e);
}
}
}
A simple way of dealing with your problem is wrapping your CompletableFuture in something with a lazy nature. You could use a Supplier or even Java 8 Stream.
it is late, but how about using constructor for first CompletableFuture in the chain?
CompletableFuture<Object> cf = new CompletableFuture<>();
// compose the chain
cf.thenCompose(sometask_here);
// later starts the chain with
cf.complete(anInputObject);
From play documentation
Whether the action code returns a Result or a Promise, both
kinds of returned object are handled internally in the same way. There
is a single kind of Action, which is asynchronous, and not two kinds
(a synchronous one and an asynchronous one). Returning a Promise is a
technique for writing non-blocking code.
does this mean that there is no difference/advantage or disadvantage in returning a Promise<Result> rather than returning a Result? If play! framework encloses calls to public static Result function() in a Promise, is there a point in the developer explicitly returning a Promise<Result>?
No, there is no point in explicitly returning a Promise<Result>, if what your code does is synchronous simply return a Result.
However, sometimes your code calls other code that returns a Promise because it performs a non-blocking asynchronous operation. In that case you should transform the promise to extract the information you need from it and then return it. By keeping it a Promise instead of unwrapping it - you're not forcing the thread to block and saving the overhead of a context switch which can be significant.
For example let's say you want to query a webservice:
WSRequestHolder holder = WS.url("someUrl");
Promise<JsonNode> json = holder.get();
Now, you can do the following:
JsonNode jsonResult = json.get(); // force the program to wait
return jsonResult; // return it
But this will force the thread to context-switch in a blocking io operation. Instead, you can return a promise directly:
return json; // return the promise
And save the overhead of context-switching, you can also use .map if you need to manipulate it first.
What's the difference between Future and Promise?
They both act like a placeholder for future results, but where is the main difference?
(I'm not completely happy with the answers so far, so here is my attempt...)
I think that Kevin Wright's comment
You can make a Promise and it's up to you to keep it. When someone else makes you a promise you must wait to see if they honour it in the Future
summarizes it pretty well, but some explanation can be useful.
Futures and promises are pretty similar concepts, the difference is that a future is a read-only container for a result that does not yet exist, while a promise can be written (normally only once). The Java 8 CompletableFuture and the Guava SettableFuture can be thought of as promises, because their value can be set ("completed"), but they also implement the Future interface, therefore there is no difference for the client.
The result of the future will be set by "someone else" - by the result of an asynchronous computation. Note how FutureTask - a classic future - must be initialized with a Callable or Runnable, there is no no-argument constructor, and both Future and FutureTask are read-only from the outside (the set methods of FutureTask are protected). The value will be set to the result of the computation from the inside.
On the other hand, the result of a promise can be set by "you" (or in fact by anybody) anytime because it has a public setter method. Both CompletableFuture and SettableFuture can be created without any task, and their value can be set at any time. You send a promise to the client code, and fulfill it later as you wish.
Note that CompletableFuture is not a "pure" promise, it can be initialized with a task just like FutureTask, and its most useful feature is the unrelated chaining of processing steps.
Also note that a promise does not have to be a subtype of future and it does not have to be the same object. In Scala a Future object is created by an asynchronous computation or by a different Promise object. In C++ the situation is similar: the promise object is used by the producer and the future object by the consumer. The advantage of this separation is that the client cannot set the value of the future.
Both Spring and EJB 3.1 have an AsyncResult class, which is similar to the Scala/C++ promises. AsyncResult does implement Future but this is not the real future: asynchronous methods in Spring/EJB return a different, read-only Future object through some background magic, and this second "real" future can be used by the client to access the result.
According to this discussion, Promise has finally been called CompletableFuture for inclusion in Java 8, and its javadoc explains:
A Future that may be explicitly completed (setting its value and status), and may be used as a CompletionStage, supporting dependent functions and actions that trigger upon its completion.
An example is also given on the list:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Note that the final API is slightly different but allows similar asynchronous execution:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
I am aware that there's already an accepted answer but would like to add my two cents nevertheless:
TLDR: Future and Promise are the two sides of an asynchronous operation: consumer/caller vs. producer/implementor.
As a caller of an asynchronous API method, you will get a Future as a handle to the computation's result. You can e.g. call get() on it to wait for the computation to complete and retrieve the result.
Now think of how this API method is actually implemented: The implementor must return a Future immediately. They are responsible for completing that future as soon as the computation is done (which they will know because it is implementing the dispatch logic ;-)). They will use a Promise/CompletableFuture to do just that: Construct and return the CompletableFuture immediately, and call complete(T result) once the computation is done.
I will give an example of what is Promise and how its value could be set at any time, in opposite to Future, which value is only readable.
Suppose you have a mom and you ask her for money.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
Output of that is:
Thank you mom for $10
Mom's promise was created , but waited for some "completion" event.
CompletableFuture<Integer> promise...
You created such event, accepting her promise and announcing your plans to thank your mom:
promise.thenAccept...
At this moment mom started open her purse...but very slow...
and father interfered much faster and completed the promise instead of your mom:
promise.complete(10);
Have you noticed an executor that I wrote explicitly?
Interestingly, if you use a default implicit executor instead (commonPool) and father is not at home, but only mom with her "slow purse", then her promise will only complete, if the program lives longer than mom needs to get money from the purse.
The default executor acts kind of like a "daemon" and does not wait for all promises to be fulfilled. I have not found a good description of this fact...
Not sure if this can be an answer but as I see what others have said for someone it may look like you need two separate abstractions for both of these concepts so that one of them (Future) is just a read-only view of the other (Promise) ... but actually this is not needed.
For example take a look at how promises are defined in javascript:
https://promisesaplus.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
The focus is on the composability using the then method like:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
which makes asynchronous computation to look like synchronous:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
which is pretty cool.
(Not as cool as async-await but async-await just removes the boilerplate ....then(function(result) {.... from it).
And actually their abstraction is pretty good as the promise constructor
new Promise( function(resolve, reject) { /* do it */ } );
allows you to provide two callbacks which can be used to either complete the Promise successfully or with an error. So that only the code that constructs the Promise can complete it and the code that receives an already constructed Promise object has the read-only view.
With inheritance the above can be achieved if resolve and reject are protected methods.
For client code, Promise is for observing or attaching callback when a result is available, whereas Future is to wait for result and then continue. Theoretically anything which is possible to do with futures what can done with promises, but due to the style difference, the resultant API for promises in different languages make chaining easier.
Future vs Promise
Future and Promise are proxy object for unknown result
Promise completes a Future
Promise - write/producer of unknown result.
Future - read/consumer of unknown result. It has next states: pending, fulfilled, canceled
//Future has a reference to Promise
Future -> Promise
As a producer I promise something and responsible for it
As a consumer who retrieved a promise I expect to have a result in future. In future I can use the promise or reject it
As for Java CompletableFutures it is a Promise because you can set the result and also it implements Future
No set method in Future interface, only get method, so it is read-only.
About CompletableFuture, this article maybe helpful.
completablefuture
In this example you can take a look at how Promises can be used in Java
for creating asynchronous sequences of calls:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));