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.
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 not able to process Mono<List<Object>> to List<Object>. I have read somewhere that flatmap can be used, but I am not able to do that either. I don't want to use .block() method for this scenario.
A code example could be:
PagePublisher<Address> someAddressPage = someService.getPagePublisherForAddress();
Mono<List<Address>> addressListMono =
Flux.from(someAddressPage.items()).collectList();
I need to get List<Address> from Mono<List<Address>>. The method return type is List<Address>.
I am not sure how to go about that and I am relatively new to reactive. Need help in that regard.
Using block() is actually the only way to get the object from a Mono when it is emitted. However, you should avoid it at all costs because it defeats the purpose of using the reactive stack given that it actually blocks the thread waiting for the object to be emitted from the Mono.
This means that while working with reactive programming you should actually work with Mono and Flux so that your application is really reactive. The consequence of this is that you must change the return type of your method to return Mono<List<Address>> instead.
Its impossible to get List<Address> from Mono<List<Address>>. If the List isn't available yet since Mono and Flux are asynchronous/non-blocking by their nature, you can't get it except by waiting until it comes in and that's what blocking is.
Ideally, your method should return Mono<List<Address>> or just Flux<Address> and the caller of this method should subscribe to the results. Since you are using Spring Webflux, complete chain should be reactive.
You can subscribe to the Mono from the calling method and the Subscriber you pass will get the List when it becomes available. E.g.
addressListMono.subscribe(
addressList -> doSomething(addressList),
error -> error.printStackTrace(),
() -> Console.out.println("completed without a value")
)
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.
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.
For example, i want to read 100500 bytes to an array:
byte[] array = new byte[100500];
int offset = 0;
ByteBuffer buf = ByteBuffer.directBuffer(4096);
channel.read(buffer, null, new LambdaAdapter((count, exception, attachment) -> {
buf.get(array, offset, count);
offset += count; //will not work, offset must be final
if (offset < 100500) {
channel.read(buffer, null, /*what here? must be lambda we are currently in but we can't use it!*/)
}
//here we have our 100500 bytes inside array
});
LambdaAdapter here is simple wrapper that converts CompletionHandler to functional interface with three arguments.
Anyway. Offset can be put to 'attachment' parameter, lambda can be declared beforehand and reused as as field. However, resulting code is always ugly Ugly UGLY.
I was not able to write acceptable solution even for such simple task - what it will look like for complex protocol where reads are interleaved with writes and wrapped in complex logic?
Does anyone know suitable way to deal with async API? If you think that Scala can save the world here, feel free to use it.
I know how to deal with with async computations IO in general, and async IO in particular. Async program should be represented as a dataflow graph, as described in Dataflow_programming. Each node has a set of inputs, each input accepts messages or signals, and fires (goes to a thread pool) when all inputs are filled. For example, a node representing a socket channel has two inputs: one for ByteBuffers and one to indicate that the channel is free and can accept IO requests. So a node resembles a function in functional programming, but can be reused - no new objects are created for next IO operation.
Scala (and Akka) actors does not fit, as each actor has only one input. Look, however, at Scala Dataflow - I did not learn it yet, but the name is promising :).
I have developed a dataflow library for java dataflow library for java, but its IO part is somewhat outdated (I am thinking of more elegant, or at least less ugly API). Look at echo server implementation in examples subdirectory.
I found acceptable solutions.
First of all, following worth looking at: https://github.com/Netflix/RxJava
As for coding guidelines...
Async method is a method that returns before doing any useful work.
Async operation code should start with creation of new object, let's call it context
Void startMyAsync(String p1, int p2, Observer callback) {
return new MyAsyncContext(p1, p2, callback).start();
}
Result of async operation method is not used - let's return Void type. It is useful since compiler will check for you that every async method calls another async method or explicitly returns null.
Async methods can throw exceptions
Async callbacks should not throw exceptions - callback error handler must be used instead
Async callbacks should only contain try...catch and context method invocation.
Async callbacks should return Void as well
Additional data provided by CompletionHandler is not needed - context fields should be used instead. If async flow does not split synchronization is not needed.
Example of async callback:
return myAsyncMethod(param1, param2, (result, exc, att) -> {
try {
if (exc != null) {
return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
} else {
return handleResult(result);
}
} catch (Exception e) {
return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
}
});