繁体   English   中英

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

[英]PlayFramework custom executors when using CompletableFutures and java

在最新版本的PlayFramework中,他们开始使用CompletionStage作为将用于异步执行的控制器的返回类型,或者简而言之,如果返回CompletionStage则是异步执行...

现在,当我们知道提交给CF的工作是长时间运行的IO操作时,我们需要传递一个自定义执行程序(否则它将默认在FJP上执行)。

每个控制器执行都有一个HTTP上下文,其中包含所有请求信息,如果使用JPA则此上下文对于拥有EntityManagers是必需的。

如果仅创建自定义ExecutorService并将其注入到控制器中以便在supplyAsync()使用,我们将不会获得所有上下文信息。

这是一些返回CompletionStage控制器动作的示例

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

}

如果我们尝试在doSomeWork()运行类似的doSomeWork()

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

或在控制器中使用JPAAPI jpa字段

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

像这样的异常

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

如您所见,jpa代码包装在事务中,但是未找到任何上下文,因为这是一个纯定制Java线程池。

使用CompletableFuture和自定义执行程序时提供所有上下文信息的正确方法是什么?

我还尝试在application.conf定义自定义执行application.conf ,并从actor系统中查找它们,但最终我将得到MessageDispatcher ,该MessageDispatcher虽然由ExecutorService支持,但与CompletableFuture不兼容(也许我错了?如果这样,如何在CF中使用它? )

您可以使用play.libs.concurrent.HttpExecution.fromThread方法:

一个ExecutionContext ,它在给定的ExecutionContext上执行工作。 当调用此方法并将其保留用于所有已执行任务时,将捕获当前线程的上下文ClassLoaderHttp.Context

因此,代码将类似于:

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

或者,如果您使用的是scala.concurrent.ExecutionContext

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

但是我不完全确定会保留用于JPA的EntityManager

暂无
暂无

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

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