2016-07-05 39 views
0

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

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

每个控制器执行有HTTP背景下,其在它所有的请求信息也这种情况下必须有你的EntityManagers如果使用JPA ...

如果我们只是创建自定义ExecutorService和它注入我们的控制器使用supplyAsync()我们不会拥有所有的上下文信息。

下面是一些控制器动作返回CompletionStage

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

}

,并在,如果我们试图在doSomeWork()

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

或使用运行像这样preinjected 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定制的执行者和演员系统查找他们,但我最终将不得不MessageDispatcher这虽然是ExecutorService支持不符合CompletableFuture(兼容或许我错了吗?如果是的话如何使用它?使用CF)

回答

1

您可以使用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)); 

但我不能完全肯定将保留EntityManager为JPA。