[英]PlayFramework passing execution context when using CompletableFutures and java
[英]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
上执行工作。 当调用此方法并将其保留用于所有已执行任务时,将捕获当前线程的上下文ClassLoader
和Http.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.