简体   繁体   English

使用CompletableFutures和Java时的PlayFramework自定义执行程序

[英]PlayFramework custom executors when using CompletableFutures and java

In latest versions of PlayFramework they started using CompletionStage as return type for controllers that will be used for async execution or in a nutshell if you return CompletionStage it is asynchronous execution... 在最新版本的PlayFramework中,他们开始使用CompletionStage作为将用于异步执行的控制器的返回类型,或者简而言之,如果返回CompletionStage则是异步执行...

Now when we know the work we submit to CF is a long running IO operation we need to pass a custom executor (otherwise it will be executed on FJP by default). 现在,当我们知道提交给CF的工作是长时间运行的IO操作时,我们需要传递一个自定义执行程序(否则它将默认在FJP上执行)。

Each controller execution has a HTTP context which has in it all the request information also this context is necessary to have your EntityManagers if you use JPA ... 每个控制器执行都有一个HTTP上下文,其中包含所有请求信息,如果使用JPA则此上下文对于拥有EntityManagers是必需的。

If we just create custom ExecutorService and inject it in our controller to use in supplyAsync() we wont have all the context information. 如果仅创建自定义ExecutorService并将其注入到控制器中以便在supplyAsync()使用,我们将不会获得所有上下文信息。

Here is an example of some controller action returning CompletionStage 这是一些返回CompletionStage控制器动作的示例

return supplyAsync(() -> {
   doSomeWork();
}, executors.io); // this is a custom CachedThreadPool with daemon thread factory

} }

and if we try to run something like this in doSomeWork() 如果我们尝试在doSomeWork()运行类似的doSomeWork()

Request request = request(); // getting request using Controller.request()

or use preinjected JPAAPI jpa field in controller 或在控制器中使用JPAAPI jpa字段

jpa.withTransaction(
    () -> jpa.em() // we will get an exception here although we are wrapped in a transaction
             ...
);

exception like 像这样的异常

No EntityManager bound to this thread. Try wrapping this call in JPAApi.withTransaction, or ensure that the HTTP context is setup on this thread.

As you can see the jpa code is wrapped in transaction but no context was found because this is a custome pure java threadpool. 如您所见,jpa代码包装在事务中,但是未找到任何上下文,因为这是一个纯定制Java线程池。

What is the correct way to provide all the context information when using CompletableFuture and custom executor? 使用CompletableFuture和自定义执行程序时提供所有上下文信息的正确方法是什么?

I also tried defining custom executors in application.conf and lookup them from actor system but i will end up having MessageDispatcher which although is backed by ExecutorService is not compatible with CompletableFuture (maybe i'm wrong? if so how to use it with CF?) 我还尝试在application.conf定义自定义执行application.conf ,并从actor系统中查找它们,但最终我将得到MessageDispatcher ,该MessageDispatcher虽然由ExecutorService支持,但与CompletableFuture不兼容(也许我错了?如果这样,如何在CF中使用它? )

You can use play.libs.concurrent.HttpExecution.fromThread method: 您可以使用play.libs.concurrent.HttpExecution.fromThread方法:

An ExecutionContext that executes work on the given ExecutionContext . 一个ExecutionContext ,它在给定的ExecutionContext上执行工作。 The current thread's context ClassLoader and Http.Context are captured when this method is called and preserved for all executed tasks. 当调用此方法并将其保留用于所有已执行任务时,将捕获当前线程的上下文ClassLoaderHttp.Context

So, the code would be something like: 因此,代码将类似于:

java.util.concurrent.Executor executor = getExecutorFromSomewhere();
return supplyAsync(() -> {
    doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(executor));

Or, if you are using a scala.concurrent.ExecutionContext : 或者,如果您使用的是scala.concurrent.ExecutionContext

scala.concurrent.ExecutionContext ec = getExecutorContext();
return supplyAsync(() -> {
    doSomeWork();
}, play.libs.concurrent.HttpExecution.fromThread(ec));

But I'm not entirely sure that will preserve the EntityManager for JPA. 但是我不完全确定会保留用于JPA的EntityManager

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM