Rupesh Patil
Rupesh Patil

Reputation: 153

How to write async actions in play framework 2.5?

I wrote the following code to send an email as non-blocking action. It's not working for more than 1 request.

CompletableFuture.supplyAsync(() -> 
 EmailService.sendVerificationMail(appUser , mailString)).
  thenApply(i -> ok("Got result: " + i));

As play.Promise is deprecated in play.2.5 (java). My previous code is not supporting. So please give me proper solution to make my action as non-blocking.

Upvotes: 2

Views: 3000

Answers (2)

Rupesh Patil
Rupesh Patil

Reputation: 153

import java.util.concurrent.CompletableFuture;

public static CompletableFuture<Result> asynchronousProcessTask() {
        final CompletableFuture<Boolean> promise = CompletableFuture
                .supplyAsync(() -> Locate365Util.doTask());
        return promise.thenApplyAsync(
                (final Boolean i) -> ok("The Result of promise" + promise));
    }

** doTask() method must return boolean value

Upvotes: 0

HKTonyLee
HKTonyLee

Reputation: 3310

If the function EmailService.sendVerificationMail is blocking, CompletableFuture only makes it non-blocking on the calling thread. In fact it is still blocking on other thread (probably the common ForkJoinPool).

This is not a problem if only several email tasks are running. But if there are too many email tasks (say 100 or more), they will "dominate" the pool. This causes "Convoy effect" and other tasks have to wait much more time to start. This can badly damage the server performance.

If you have a lot of concurrent email tasks, you can create your own pool to handles them, instead of using the common pool. Thread pool is better than fork join pool because it does not allow work-stealing.

Or you can find the asynchronous APIs of EmailService, or implement them on your own if possible.

To answer the other question, now Play 2.5 uses CompletionStage for the default promise. It should work if you just use CompletionStage.

Some example code here. Note the use of CompletionStage in the return type.

public CompletionStage<Result> testAction() {
    return CompletableFuture
            .supplyAsync(() -> EmailService.sendVerificationMail(appUser, mailString), EmailService.getExecutor())
            .thenApply(i -> ok("Got result: " + i));
}

For more details, you may check the Java Migration Guide on Play's site.

Upvotes: 3

Related Questions