Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play framework async processing and blocking I/O in Java

My application uses Play framework to process REST requests. I need to perform some potentially long lasting blocking I/O operation in http request handler. In parallel I'd like to handle efficiently some short lasting requests.

As described here:

http://www.playframework.com/documentation/2.2.0/JavaAsync

long lasting operation can be run asynchronously. On the other hand, as described here:

http://www.playframework.com/documentation/2.2.x/ThreadPools

Play framework uses the same default thread pool, in which all application code is executed. At least in Java api there is no possibility to run asynchronous work on different thread pool.

So, my question is if it's worth to run the potentially blocking I/O operation asynchronously, considering the fact that such an operation uses the same thread pool anyway. Or maybe it's better to increase the default thread pool size, and don't bother with async api in such a case? (this way at least code readability would be much higher)

like image 368
oo_olo_oo Avatar asked Mar 20 '14 14:03

oo_olo_oo


People also ask

Is Play framework asynchronous?

Internally, Play Framework is asynchronous from the bottom up. Play handles every request in an asynchronous, non-blocking way. The default configuration is tuned for asynchronous controllers.

What is asynchronous processing in Java?

Asynchronous programming in Java is a technique for parallel programming that lets teams distribute work and build application features separately from the primary application thread. Then, when the team is ready with the feature, the code is synced with the main thread.

Does Java have async?

2.2. FutureTask. Since Java 5, the Future interface provides a way to perform asynchronous operations using the FutureTask. We can use the submit method of the ExecutorService to perform the task asynchronously and return the instance of the FutureTask.

Is Scala asynchronous?

The Scala asynchronous programming (AP) API supports both Concurrency and true Parallelism very well, in an asynchronous way.


1 Answers

I would recommend that you set up your own context and run your blocking/cpu-intensive operations there using Plays F.Promise<A>. As always with threads, the optimal solution depends on numerous of things like number of cores etc.

First set up your context in applications.conf:

play {
  akka {
    akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
    loglevel = WARNING
    actor {
      default-dispatcher = {
        fork-join-executor {
          parallelism-min = 1
          parallelism-factor = 2
          parallelism-max = 6
        }
      }
      my-context {
        fork-join-executor {
          parallelism-min = 1
          parallelism-factor = 4
          parallelism-max = 16
        }
      }
    }
  }
}

Then in your controller, make use of your context using Plays Promises (I'm using Java 8):

public static F.Promise<Result> love() {
    ExecutionContext myExecutionContext = Akka.system().dispatchers().lookup("play.akka.actor.my-context");

    F.Promise<Integer> integerPromise = F.Promise.promise(() ->
            LongRunningProcess.run(10000L)
    , myExecutionContext);

    F.Promise<Integer> integerPromise2 = F.Promise.promise(() ->
            LongRunningProcess.run(10000L)
    , myExecutionContext);

    return integerPromise.flatMap(i -> integerPromise2.map(x -> ok()));
}

This way your Play app will still handle short lasting requests on the default-dispatcher execution context and the blocking/cpu-intensive will run in my-context.

I made a very short example for you demonstrating this, check it out on github.

like image 59
Franz Avatar answered Sep 21 '22 15:09

Franz