2016-07-05 40 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。